diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2018-10-30 08:13:57 +0100 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2018-10-30 08:14:00 +0100 |
commit | 8aa7bd47d35f9c6b699e4d4c8cc24911ba9443ff (patch) | |
tree | 7b7a928ef761e54e405f68436f5f8d51939ed497 | |
parent | a4f7ce5f65621de768510e11da5762c3c7b2a983 (diff) | |
parent | 6e2741e3e38c09a014efc9cb0079ef942ff54626 (diff) |
Merge remote-tracking branch 'origin/5.12' into dev
Change-Id: I4fb74ab92e03dd13e054227deac2bd095c47bce0
45 files changed, 704 insertions, 819 deletions
diff --git a/README.pyside2.md b/README.pyside2.md index cde05940d..53f7bc9d0 100644 --- a/README.pyside2.md +++ b/README.pyside2.md @@ -2,52 +2,70 @@ ### 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. +PySide is the [Python Qt bindings project](http://wiki.qt.io/Qt_for_Python), +providing access to the complete Qt 5.12+ framework as well as to generator +tools for rapidly generating Python 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/). +### Installation -PySide 2 supports Qt5. For building, please read about -[getting started](https://wiki.qt.io/PySide2_GettingStarted). -Then download the sources by running +Since the release of the [Technical Preview](https://blog.qt.io/blog/2018/06/13/qt-python-5-11-released/) +it is possible to install via `pip`, both from Qt's servers +and [PyPi](https://pypi.org/project/PySide2/): - git clone https://code.qt.io/pyside/pyside-setup - -### Building + pip install PySide2 #### 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 +PySide versions following 5.12 use a C++ parser based on +[Clang](http://clang.org/). The Clang library (C-bindings), version 6.0 or higher is required for building. Prebuilt versions of it can be downloaded from [download.qt.io](http://download.qt.io/development_releases/prebuilt/libclang/). 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 + 7z x .../libclang-release_60-linux-Rhel7.2-gcc5.3-x86_64-clazy.7z export LLVM_INSTALL_DIR=$PWD/libclang On Windows: - 7z x .../libclang-release_39-windows-vs2015_64.7z + 7z x .../libclang-release_60-windows-vs2015_64-clazy.7z SET LLVM_INSTALL_DIR=%CD%\libclang -#### Build Instructions +### Building from source -You might consider using a virtual environment as described at -[getting started](https://wiki.qt.io/PySide2_GettingStarted). -You should be able to build: +For building PySide2 from scratch, please read about +[getting started](https://wiki.qt.io/Qt_for_Python/GettingStarted). +This process will include getting the code: + git clone https://code.qt.io/pyside/pyside-setup cd pyside-setup - python setup.py install + git branch --track 5.12 origin/5.12 + git checkout 5.12 + +then install the dependencies, and following the instructions per platform. +A common build command will look like: + + python setup.py install --qmake=<path/to/qmake/> --jobs=8 --build-tests + +You can obtain more information about the options to build PySide +and Shiboken in [our wiki](https://wiki.qt.io/Qt_for_Python/). + +### Documentation and Bugs + +You can find more information about the PySide2 module API in the +[official Qt for Python documentation](https://doc.qt.io/qtforpython/). + +If you come across any issue, please file a bug report at our +[JIRA tracker](https://bugreports.qt.io/projects/PYSIDE) following +our [guidelines](https://wiki.qt.io/Qt_for_Python/Reporting_Bugs). + +### Community -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. +Check *#qt-pyside*, our official IRC channel on FreeNode, +or contact us via our [mailing list](http://lists.qt-project.org/mailman/listinfo/pyside). diff --git a/README.shiboken2-generator.md b/README.shiboken2-generator.md index c71c6a8de..f29f40634 100644 --- a/README.shiboken2-generator.md +++ b/README.shiboken2-generator.md @@ -1 +1,37 @@ # shiboken2-generator + +Shiboken is the generator used by the Qt for Python project. +It outputs C++ code for CPython extensions, which can be compiled +and transformed into a Python module. + +C++ projects based on Qt can be wrapped, but also projects +which are not related to Qt. + +## How does it work? + +Shiboken uses an API Extractor that does most of the job, +but it requires a typesystem (XML file) to customize how the +C++ classes/methods will be exposed to Python. + +The typesystem allows you to remove arguments from signatures, +modify return types, inject code and add conversion rules +from the C++ data types to Python data types, manipulate +the ownership of the objects, etc. + +# Examples + +An example related to wrap a C++ library not depending on Qt +can be found in our [repository](https://code.qt.io/cgit/pyside/pyside-setup.git/tree/examples/samplebinding). + +Additionally, you can find a couple of tests inside the +[git repository](https://code.qt.io/cgit/pyside/pyside-setup.git/tree/sources/shiboken2/tests). + +For a more advanced case regarding extending a Qt/C++ application +with Python bindings based on the idea of the PySide module, +you can check the [scriptableapplication](https://code.qt.io/cgit/pyside/pyside-setup.git/tree/examples/scriptableapplication) +example in our repository. + +# Documentation + +You can find more information about Shiboken in our +[official documentation page](https://doc.qt.io/qtforpython/shiboken2/). diff --git a/README.shiboken2.md b/README.shiboken2.md index f98f63c57..d9cd32a40 100644 --- a/README.shiboken2.md +++ b/README.shiboken2.md @@ -1 +1,13 @@ # shiboken2 module + +The purpose of the shiboken2 Python module is to access information +related to the binding generation that could be used to integrate +C++ programs to Python, or even to get useful information to debug +an application. + +Mostly the idea is to interact with Shiboken objects, +where one can check if it is valid, or if the generated Python wrapper +is invalid after the underlying C++ object has been destroyed. + +More information on the available functions can be found +in our [official documentation](https://doc.qt.io/qtforpython/shiboken2/shibokenmodule.html) diff --git a/build_scripts/options.py b/build_scripts/options.py index daf3bb00e..3e3a63ca9 100644 --- a/build_scripts/options.py +++ b/build_scripts/options.py @@ -40,8 +40,13 @@ from __future__ import print_function import sys import os +import warnings +def _warn_multiple_option(option): + w = 'Option "{}" occurs multiple times on the command line.'.format(option) + warnings.warn(w) + class Options(object): def __init__(self): @@ -51,13 +56,13 @@ class Options(object): 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 + option = '--' + name + count = sys.argv.count(option) + for i in range(count): + sys.argv.remove(option) + if count > 1: + _warn_multiple_option(option) + return count > 0 def option_value(self, name, remove=True): """ @@ -73,30 +78,36 @@ class Options(object): :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] + option = '--' + name + single_option_prefix = option + '=' + value = None + for index in reversed(range(len(sys.argv))): + arg = sys.argv[index] + if arg == option: + if value: + _warn_multiple_option(option) + else: + 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:] + elif arg.startswith(single_option_prefix): + if value: + _warn_multiple_option(option) + else: + value = arg[len(single_option_prefix):] if remove: sys.argv[index:index + 1] = [] - self.dict[name] = value - return value + if value is None: + value = os.getenv(name.upper().replace('-', '_')) - env_val = os.getenv(name.upper().replace('-', '_')) - self.dict[name] = env_val - return env_val + self.dict[name] = value + return value options = Options() diff --git a/missing_bindings.py b/missing_bindings.py index ad7cfce52..dfd94912d 100644 --- a/missing_bindings.py +++ b/missing_bindings.py @@ -106,7 +106,7 @@ modules_to_test['QtX11Extras'] = 'qtx11extras-module.html' modules_to_test['QtWinExtras'] = 'qtwinextras-module.html' modules_to_test['QtXml'] = 'qtxml-module.html' modules_to_test['QtXmlPatterns'] = 'qtxmlpatterns-module.html' -modules_to_test['QtCharts'] = 'qt-charts-module.html' +modules_to_test['QtCharts'] = 'qtcharts-module.html' modules_to_test['QtDataVisualization'] = 'qtdatavisualization-module.html' types_to_ignore = set() @@ -216,7 +216,7 @@ qt_documentation_website_prefixes['5.6'] = 'http://doc.qt.io/qt-5.6/' qt_documentation_website_prefixes['5.8'] = 'http://doc.qt.io/qt-5.8/' qt_documentation_website_prefixes['5.9'] = 'http://doc.qt.io/qt-5.9/' qt_documentation_website_prefixes['5.10'] = 'http://doc.qt.io/qt-5.10/' -qt_documentation_website_prefixes['5.11'] = 'http://doc.qt.io/qt-5/' +qt_documentation_website_prefixes['5.11'] = 'http://doc.qt.io/qt-5.11/' qt_documentation_website_prefixes['dev'] = 'http://doc-snapshots.qt.io/qt5-dev/' @@ -347,8 +347,12 @@ for module_name in modules_to_test.keys(): continue try: + pyqt_module_name = module_name + if module_name == "QtCharts": + pyqt_module_name = module_name[:-1] + pyqt_tested_module = getattr(__import__(pyqt_package_name, - fromlist=[module_name]), module_name) + fromlist=[pyqt_module_name]), pyqt_module_name) except Exception as e: log("\nCould not load {}.{} for comparison. " "Received error: {}.\n".format(pyqt_package_name, module_name, @@ -378,13 +382,13 @@ for module_name in modules_to_test.keys(): try: pyside_qualified_type = 'pyside_tested_module.' - if "Charts" in module_name: + if "QtCharts" == module_name: pyside_qualified_type += 'QtCharts.' elif "DataVisualization" in module_name: pyside_qualified_type += 'QtDataVisualization.' pyside_qualified_type += qt_type - o = eval(pyside_qualified_type) + eval(pyside_qualified_type) except: missing_type = qt_type missing_types_count += 1 diff --git a/sources/cmake_helpers/helpers.cmake b/sources/cmake_helpers/helpers.cmake index dd2e98a3a..e64b8d9d3 100644 --- a/sources/cmake_helpers/helpers.cmake +++ b/sources/cmake_helpers/helpers.cmake @@ -61,3 +61,18 @@ macro(compute_config_py_values endif() endmacro() + +# Creates a new target called "${library_name}_generator" which +# depends on the mjb_rejected_classes.log file generated by shiboken. +# This target is added as a dependency to ${library_name} target. +# This file's timestamp informs cmake when the last generation was +# done, without force-updating the timestamps of the generated class +# cpp files. +# In practical terms this means that changing some injection code in +# an xml file that modifies only one specific class cpp file, will +# not force rebuilding all the cpp files, and thus allow for better +# incremental builds. +macro(create_generator_target library_name) + add_custom_target(${library_name}_generator DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log") + add_dependencies(${library_name} ${library_name}_generator) +endmacro() diff --git a/sources/pyside2/PySide2/Qt3DCore/typesystem_3dcore.xml b/sources/pyside2/PySide2/Qt3DCore/typesystem_3dcore.xml index fb7a83ba7..013a49165 100644 --- a/sources/pyside2/PySide2/Qt3DCore/typesystem_3dcore.xml +++ b/sources/pyside2/PySide2/Qt3DCore/typesystem_3dcore.xml @@ -45,19 +45,41 @@ <namespace-type name="Qt3DCore"> <enum-type name="ChangeFlag" flags="ChangeFlags"/> <object-type name="QAbstractAspect"/> + <object-type name="QAbstractEngine"/> <object-type name="QAbstractSkeleton" since="5.10"/> <object-type name="QArmature" since="5.10"/> - <object-type name="QAspectEngine"/> + <object-type name="QAspectEngine"> + <modify-function signature="registerAspect(Qt3DCore::QAbstractAspect*)"> + <modify-argument index="this"> + <parent index="1" action="add"/> + </modify-argument> + </modify-function> + </object-type> <object-type name="QAspectJob"/> <object-type name="QBackendNode"> <enum-type name="Mode"/> </object-type> + <!-- TODO: Solve issues related to windows and a unresolved + external symbol + <object-type name="QBackendNodeMapper"/>--> <object-type name="QComponent"/> <object-type name="QComponentAddedChange"/> <object-type name="QComponentRemovedChange"/> <object-type name="QDynamicPropertyUpdatedChange"/> - <object-type name="QEntity"/> - <object-type name="QJoint" since="5.10"/> + <object-type name="QEntity"> + <modify-function signature="addComponent(Qt3DCore::QComponent*)"> + <modify-argument index="this"> + <parent index="1" action="add"/> + </modify-argument> + </modify-function> + </object-type> + <object-type name="QJoint" since="5.10"> + <modify-function signature="addChildJoint(Qt3DCore::QJoint*)"> + <modify-argument index="this"> + <parent index="1" action="add"/> + </modify-argument> + </modify-function> + </object-type> <object-type name="QNode"> <enum-type name="PropertyTrackingMode"/> </object-type> @@ -88,5 +110,10 @@ <!-- Disambiguate from QtGui/qtransform.h --> <include file-name="Qt3DCore/qtransform.h" location="global"/> </object-type> + <namespace-type name="Quick"> + <object-type name="QQmlAspectEngine"> + <enum-type name="Status"/> + </object-type> + </namespace-type> </namespace-type> </typesystem> diff --git a/sources/pyside2/PySide2/Qt3DInput/typesystem_3dinput.xml b/sources/pyside2/PySide2/Qt3DInput/typesystem_3dinput.xml index f2b408257..ebac94f03 100644 --- a/sources/pyside2/PySide2/Qt3DInput/typesystem_3dinput.xml +++ b/sources/pyside2/PySide2/Qt3DInput/typesystem_3dinput.xml @@ -45,7 +45,9 @@ <namespace-type name="Qt3DInput"> <object-type name="QAbstractActionInput"/> <object-type name="QAbstractAxisInput"/> - <object-type name="QAbstractPhysicalDevice"/> + <object-type name="QAbstractPhysicalDevice"> + <enum-type name="DeviceStatus"/> + </object-type> <object-type name="QAction"/> <object-type name="QActionInput"/> <object-type name="QAnalogAxisInput"/> @@ -57,12 +59,17 @@ <object-type name="QButtonAxisInput"/> <object-type name="QInputAspect"/> <object-type name="QInputChord"/> + <!-- On windows this raises the following error: + type 'Qt3DInput::QInputDeviceIntegration' is specified in typesystem, but not defined. + This could potentially lead to compilation errors. + <object-type name="QInputDeviceIntegration"/> + --> <object-type name="QInputSequence"/> <object-type name="QInputSettings"/> + <object-type name="QKeyboardDevice"/> <object-type name="QKeyboardHandler"/> <object-type name="QKeyEvent"/> <object-type name="QLogicalDevice"/> - <object-type name="QKeyboardDevice"/> <object-type name="QMouseDevice"> <enum-type name="Axis"/> </object-type> @@ -75,5 +82,11 @@ <enum-type name="Modifiers"/> </object-type> <object-type name="QMouseHandler"/> + <!-- On windows this raise the following error: + qt3dinput_module_wrapper.cpp.obj : error LNK2019: + unresolved external symbol "void __cdecl init_Qt3DInput_QPhysicalDeviceCreatedChangeBase(struct _object *)" + (?init_Qt3DInput_QPhysicalDeviceCreatedChangeBase@@YAXPAU_object@@@Z) referenced in function _PyInit_Qt3DInput + <object-type name="QPhysicalDeviceCreatedChangeBase"/> + --> </namespace-type> </typesystem> diff --git a/sources/pyside2/PySide2/QtCore/CMakeLists.txt b/sources/pyside2/PySide2/QtCore/CMakeLists.txt index 466e97756..e583bd0f4 100644 --- a/sources/pyside2/PySide2/QtCore/CMakeLists.txt +++ b/sources/pyside2/PySide2/QtCore/CMakeLists.txt @@ -16,6 +16,7 @@ ${QtCore_GEN_DIR}/qabstracteventdispatcher_timerinfo_wrapper.cpp ${QtCore_GEN_DIR}/qabstracteventdispatcher_wrapper.cpp ${QtCore_GEN_DIR}/qabstractitemmodel_wrapper.cpp ${QtCore_GEN_DIR}/qabstractlistmodel_wrapper.cpp +${QtCore_GEN_DIR}/qabstractnativeeventfilter_wrapper.cpp ${QtCore_GEN_DIR}/qabstractproxymodel_wrapper.cpp ${QtCore_GEN_DIR}/qabstractstate_wrapper.cpp ${QtCore_GEN_DIR}/qabstracttablemodel_wrapper.cpp diff --git a/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml b/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml index 838d95896..005fd0684 100644 --- a/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml +++ b/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml @@ -74,6 +74,10 @@ <function signature="qVersion()" /> <function signature="qrand()" /> <function signature="qsrand(uint)" /> + <function signature="qCompress(const uchar*,int,int)"/> + <function signature="qCompress(const QByteArray&,int)"/> + <function signature="qUncompress(const uchar*,int)"/> + <function signature="qUncompress(const QByteArray&)"/> <inject-code class="native" position="beginning"> #include <pyside.h> @@ -938,9 +942,6 @@ <rejection class="" enum-name="QtValidLicenseForGuiModule"/> <rejection class="" enum-name="QtValidLicenseForScriptModule"/> <rejection class="" enum-name="QtValidLicenseForHelpModule"/> - <rejection class="QAbstractEventDispatcher" function-name="filterEvent"/> - <rejection class="QAbstractEventDispatcher" function-name="filterNativeEvent"/> - <rejection class="QAbstractEventDispatcher" function-name="setEventFilter"/> <!-- Internal --> <rejection class="QAbstractFileEngine"/> <!-- <rejection class="QAbstractFileEngine" function-name="endEntryList"/> @@ -2978,6 +2979,26 @@ <object-type name="QXmlStreamEntityResolver"/> <!-- Qt5: had to move QAbstractEventDispatcher into os-specific files because of Windows --> + <object-type name="QAbstractNativeEventFilter"> + <!-- see QWidget::nativeEvent(), QWindow::nativeEvent() --> + <modify-function signature="nativeEventFilter(const QByteArray&,void*,long*)"> + <modify-argument index="3"> + <remove-argument/> + <conversion-rule class="native"> + <insert-template name="return_native_eventfilter_conversion_variables"/> + </conversion-rule> + </modify-argument> + <modify-argument index="return"> + <replace-type modified-type="PyObject"/> + <conversion-rule class="native"> + <insert-template name="return_native_eventfilter_conversion"/> + </conversion-rule> + </modify-argument> + <inject-code position="end"> + <insert-template name="return_native_eventfilter"/> + </inject-code> + </modify-function> + </object-type> <object-type name="QEventLoop"> <enum-type name="ProcessEventsFlag" flags="ProcessEventsFlags"/> diff --git a/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml b/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml index 32d586631..e2e3b2335 100644 --- a/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml +++ b/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml @@ -2987,11 +2987,26 @@ <enum-type name="AncestorMode"/> <enum-type name="Visibility"/> <modify-function signature="raise()" rename="raise_" /> + <!-- see QWidget::nativeEvent(), QAbstractNativeEventFilter::nativeEventFilter() --> + <modify-function signature="nativeEvent(const QByteArray &,void*,long*)"> + <modify-argument index="3"> + <remove-argument/> + <conversion-rule class="native"> + <insert-template name="return_native_eventfilter_conversion_variables"/> + </conversion-rule> + </modify-argument> + <modify-argument index="return"> + <replace-type modified-type="PyObject"/> + <conversion-rule class="native"> + <insert-template name="return_native_eventfilter_conversion"/> + </conversion-rule> + </modify-argument> + <inject-code position="end"> + <insert-template name="return_native_eventfilter"/> + </inject-code> + </modify-function> </object-type> - <!-- Qt5: not sure if this needs support, skipped for now --> - <rejection class="QWindow" function-name="nativeEvent"/>" - <object-type name="QGuiApplication"> <extra-includes> <include file-name="QBasicTimer" location="global"/> diff --git a/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp b/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp index 4e45cfdcc..9d9ddc799 100644 --- a/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp +++ b/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp @@ -172,13 +172,13 @@ int PySide::qmlRegisterType(PyObject *pyObj, const char *uri, int versionMajor, type.versionMajor = versionMajor; type.versionMinor = versionMinor; type.elementName = qmlName; - type.metaObject = metaObject; type.extensionObjectCreate = 0; type.extensionMetaObject = 0; type.customParser = 0; ++nextType; } + type.metaObject = metaObject; // Snapshot may have changed. int qmlTypeId = QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); if (qmlTypeId == -1) { @@ -235,7 +235,7 @@ void propListTpFree(void* self) static PyType_Slot PropertyListType_slots[] = { {Py_tp_init, (void *)propListTpInit}, {Py_tp_free, (void *)propListTpFree}, - {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {Py_tp_dealloc, (void *)object_dealloc}, {0, 0} }; static PyType_Spec PropertyListType_spec = { @@ -449,7 +449,7 @@ static PyType_Slot QtQml_VolatileBoolType_slots[] = { {Py_tp_str, (void *)reinterpret_cast<reprfunc>(QtQml_VolatileBoolObject_str)}, {Py_tp_methods, (void *)QtQml_VolatileBoolObject_methods}, {Py_tp_new, (void *)QtQml_VolatileBoolObject_new}, - {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {Py_tp_dealloc, (void *)object_dealloc}, {0, 0} }; static PyType_Spec QtQml_VolatileBoolType_spec = { diff --git a/sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml b/sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml index 1f2cd446b..d92540d85 100644 --- a/sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml +++ b/sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml @@ -2197,8 +2197,24 @@ </object-type> <object-type name="QWidget" delete-in-main-thread="true"> - <!-- Qt5: remove native event for now --> - <modify-function signature="nativeEvent(const QByteArray &,void*,long*)" remove="all" /> + <!-- see QWindow::nativeEvent(), QAbstractNativeEventFilter::nativeEventFilter() --> + <modify-function signature="nativeEvent(const QByteArray &,void*,long*)"> + <modify-argument index="3"> + <remove-argument/> + <conversion-rule class="native"> + <insert-template name="return_native_eventfilter_conversion_variables"/> + </conversion-rule> + </modify-argument> + <modify-argument index="return"> + <replace-type modified-type="PyObject"/> + <conversion-rule class="native"> + <insert-template name="return_native_eventfilter_conversion"/> + </conversion-rule> + </modify-argument> + <inject-code position="end"> + <insert-template name="return_native_eventfilter"/> + </inject-code> + </modify-function> <extra-includes> <include file-name="QIcon" location="global"/> diff --git a/sources/pyside2/PySide2/typesystem_templates.xml b/sources/pyside2/PySide2/typesystem_templates.xml index 1a140906b..a7a7bfc9d 100644 --- a/sources/pyside2/PySide2/typesystem_templates.xml +++ b/sources/pyside2/PySide2/typesystem_templates.xml @@ -361,6 +361,26 @@ Py_INCREF(%PYARG_0); </template> + <!-- Helpers for modifying "bool nativeEventFilter(QByteArray, void*, long *result)" + to return a tuple of bool,long --> + <template name="return_native_eventfilter_conversion_variables"> + long resultVar{0}; + long *%out = &resultVar; + </template> + <template name="return_native_eventfilter_conversion"> + %RETURN_TYPE %out = false; + if (PySequence_Check(%PYARG_0) && (PySequence_Size(%PYARG_0) == 2)) { + Shiboken::AutoDecRef pyItem(PySequence_GetItem(%PYARG_0, 0)); + %out = %CONVERTTOCPP[bool](pyItem); + } + </template> + + <template name="return_native_eventfilter"> + %PYARG_0 = PyTuple_New(2); + PyTuple_SET_ITEM(%PYARG_0, 0, %CONVERTTOPYTHON[%RETURN_TYPE](%0)); + PyTuple_SET_ITEM(%PYARG_0, 1, %CONVERTTOPYTHON[long](*result_out)); + </template> + <!-- templates for __reduce__ --> <template name="reduce_code"> %PYARG_0 = Py_BuildValue("(N(%REDUCE_FORMAT))", PyObject_Type(%PYSELF), %REDUCE_ARGS); diff --git a/sources/pyside2/cmake/Macros/PySideModules.cmake b/sources/pyside2/cmake/Macros/PySideModules.cmake index 816190612..0f8b500ac 100644 --- a/sources/pyside2/cmake/Macros/PySideModules.cmake +++ b/sources/pyside2/cmake/Macros/PySideModules.cmake @@ -80,7 +80,8 @@ macro(create_pyside_module get_filename_component(pyside_binary_dir ${CMAKE_CURRENT_BINARY_DIR} DIRECTORY) - add_custom_command(OUTPUT ${${module_sources}} + add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log" + BYPRODUCTS ${${module_sources}} COMMAND "${SHIBOKEN_BINARY}" ${GENERATOR_EXTRA_FLAGS} "${pyside2_BINARY_DIR}/${module_name}_global.h" --include-paths=${shiboken_include_dirs} @@ -112,6 +113,7 @@ macro(create_pyside_module if(${module_deps}) add_dependencies(${module_name} ${${module_deps}}) endif() + create_generator_target(${module_name}) # install install(TARGETS ${module_name} LIBRARY DESTINATION ${PYTHON_SITE_PACKAGES}/PySide2) diff --git a/sources/pyside2/libpyside/CMakeLists.txt b/sources/pyside2/libpyside/CMakeLists.txt index 101b32e4a..ec6713b62 100644 --- a/sources/pyside2/libpyside/CMakeLists.txt +++ b/sources/pyside2/libpyside/CMakeLists.txt @@ -82,7 +82,8 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${SHIBOKEN_INCLUDE_DIR} ${SHIBOKEN_PYTHON_INCLUDE_DIR} ${QML_INCLUDES} - ${Qt5Core_INCLUDE_DIRS}) + ${Qt5Core_INCLUDE_DIRS} + ${Qt5Core_PRIVATE_INCLUDE_DIRS}) add_library(pyside2 SHARED ${libpyside_SRC} ${other_files}) target_link_libraries(pyside2 ${SHIBOKEN_PYTHON_LIBRARIES} diff --git a/sources/pyside2/libpyside/dynamicqmetaobject.cpp b/sources/pyside2/libpyside/dynamicqmetaobject.cpp index 525e24f4a..5cbfa70f9 100644 --- a/sources/pyside2/libpyside/dynamicqmetaobject.cpp +++ b/sources/pyside2/libpyside/dynamicqmetaobject.cpp @@ -50,521 +50,371 @@ #include <QtCore/QByteArray> #include <QtCore/QObject> #include <QtCore/QStringList> +#include <QtCore/QTextStream> #include <QtCore/QVector> +#include <private/qmetaobjectbuilder_p.h> #include <cstring> - -#define EMPTY_META_METHOD "0()" +#include <vector> using namespace PySide; -enum PropertyFlags { - Invalid = 0x00000000, - Readable = 0x00000001, - Writable = 0x00000002, - Resettable = 0x00000004, - EnumOrFlag = 0x00000008, - StdCppSet = 0x00000100, -// Override = 0x00000200, - Constant = 0x00000400, - Final = 0x00000800, - Designable = 0x00001000, - ResolveDesignable = 0x00002000, - Scriptable = 0x00004000, - ResolveScriptable = 0x00008000, - Stored = 0x00010000, - ResolveStored = 0x00020000, - Editable = 0x00040000, - ResolveEditable = 0x00080000, - User = 0x00100000, - ResolveUser = 0x00200000, - Notify = 0x00400000 -}; - -// these values are from moc source code, generator.cpp:66 -enum MethodFlags { - AccessPrivate = 0x00, - AccessProtected = 0x01, - AccessPublic = 0x02, - MethodMethod = 0x00, - MethodSignal = 0x04, - MethodSlot = 0x08, - MethodConstructor = 0x0c, - MethodCompatibility = 0x10, - MethodCloned = 0x20, - MethodScriptable = 0x40 -}; - -enum MetaDataFlags { - IsUnresolvedType = 0x80000000, - TypeNameIndexMask = 0x7FFFFFFF -}; - -class DynamicQMetaObject::DynamicQMetaObjectPrivate +// MetaObjectBuilder: Provides the QMetaObject's returned by +// QObject::metaObject() for PySide2 objects. There are several +// scenarios to consider: +// 1) A plain Qt class (say QTimer) is instantiated. In that case, +// return the base meta object until a modification is made by +// adding methods, properties or class info (cf qmetaobject_test.py). +// In that case, instantiate a QMetaObjectBuilder inheriting the +// base meta meta object, add the method and return the result +// of QMetaObjectBuilder::toMetaObject() (with dirty handling should +// further modifications be made). +// 2) A Python class inheriting a Qt class is instantiated. For this, +// instantiate a QMetaObjectBuilder and add the methods/properties +// found by inspecting the Python class. + +class MetaObjectBuilderPrivate { public: - QList<MethodData> m_methods; - QList<PropertyData> m_properties; - - QMap<QByteArray, QByteArray> m_info; - QByteArray m_className; - - bool m_updated = false; // when the meta data is not update - int m_methodOffset = 0; - int m_propertyOffset = 0; - int m_dataSize = 0; - int m_emptyMethod = -1; - int m_nullIndex = 0; - - int createMetaData(QMetaObject* metaObj); - void updateMetaObject(QMetaObject* metaObj); - void writeMethodsData(const QList<MethodData>& methods, unsigned int** data, - QByteArrayList& strings, int* prtIndex, - int nullIndex, int flags); - void writeStringData(char *, const QByteArrayList& strings) const; + using MetaObjects = std::vector<const QMetaObject *>; + + QMetaObjectBuilder *ensureBuilder(); + void parsePythonType(PyTypeObject *type); + int indexOfMethod(QMetaMethod::MethodType mtype, + const QByteArray &signature) const; + int indexOfProperty(const QByteArray &name) const; + int addSlot(const QByteArray &signature); + int addSlot(const QByteArray &signature, const QByteArray &type); + int addSignal(const QByteArray &signature); + void removeMethod(QMetaMethod::MethodType mtype, int index); int getPropertyNotifyId(PySideProperty *property) const; -}; + int addProperty(const QByteArray &property, PyObject *data); + void addInfo(const QByteArray &key, const QByteArray &value); + void addInfo(const QMap<QByteArray, QByteArray> &info); + void removeProperty(int index); + const QMetaObject *update(); -bool sortMethodSignalSlot(const MethodData &m1, const MethodData &m2) -{ - if (m1.methodType() == QMetaMethod::Signal) - return m2.methodType() == QMetaMethod::Slot; - return false; -} + QMetaObjectBuilder *m_builder = nullptr; -static int registerString(const QByteArray& s, QByteArrayList& strings) -{ - int idx = strings.indexOf(s); - if (idx == -1) { - idx = strings.size(); - strings.append(s); - } - return idx; -} - -static int blobSize(const QByteArrayList &strings) -{ - int size = strings.size() * int(sizeof(QByteArrayData)); - for (const QByteArray &field : strings) - size += field.size() + 1; - return size; -} - -static int aggregateParameterCount(const QList<MethodData> &methods) -{ - int sum = 0; - for (const auto &method : methods) - sum += method.parameterCount() * 2 + 1; // nb_param*2 (type and names) +1 for return type - return sum; -} + const QMetaObject *m_baseObject = nullptr; + MetaObjects m_cachedMetaObjects; + bool m_dirty = true; +}; -static void writeString(char *out, int i, const QByteArray &str, - const int offsetOfStringdataMember, int &stringdataOffset) +QMetaObjectBuilder *MetaObjectBuilderPrivate::ensureBuilder() { - int size = str.size(); - qptrdiff offset = offsetOfStringdataMember + stringdataOffset - - i * sizeof(QByteArrayData); - const QByteArrayData data = - Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, offset); - - memcpy(out + i * sizeof(QByteArrayData), &data, sizeof(QByteArrayData)); - - memcpy(out + offsetOfStringdataMember + stringdataOffset, str.constData(), size); - out[offsetOfStringdataMember + stringdataOffset + size] = '\0'; - - stringdataOffset += size + 1; + if (!m_builder) { + m_builder = new QMetaObjectBuilder(); + m_builder->setClassName(m_baseObject->className()); + m_builder->setSuperClass(m_baseObject); + } + return m_builder; } -static int qvariant_nameToType(const char* name) +MetaObjectBuilder::MetaObjectBuilder(const char *className, const QMetaObject *metaObject) : + m_d(new MetaObjectBuilderPrivate) { - if (!name) - return 0; - - if (strcmp(name, "QVariant") == 0) - return 0xffffffff; - if (strcmp(name, "QCString") == 0) - return QMetaType::QByteArray; - if (strcmp(name, "Q_LLONG") == 0) - return QMetaType::LongLong; - if (strcmp(name, "Q_ULLONG") == 0) - return QMetaType::ULongLong; - if (strcmp(name, "QIconSet") == 0) - return QMetaType::QIcon; - - uint tp = QMetaType::type(name); - return tp < QMetaType::User ? tp : 0; + m_d->m_baseObject = metaObject; + m_d->m_builder = new QMetaObjectBuilder(); + m_d->m_builder->setClassName(className); + m_d->m_builder->setSuperClass(metaObject); + m_d->m_builder->setClassName(className); } -/* - Returns true if the type is a QVariant types. -*/ -static bool isVariantType(const char* type) +MetaObjectBuilder::MetaObjectBuilder(PyTypeObject *type, const QMetaObject *metaObject) + : m_d(new MetaObjectBuilderPrivate) { - return qvariant_nameToType(type) != 0; + m_d->m_baseObject = metaObject; + const char *className = type->tp_name; + if (const char *lastDot = strrchr(type->tp_name, '.')) + className = lastDot + 1; + // Different names indicate a Python class inheriting a Qt class. + // Parse the type. + if (strcmp(className, metaObject->className()) != 0) { + m_d->m_builder = new QMetaObjectBuilder(); + m_d->m_builder->setClassName(className); + m_d->m_builder->setSuperClass(metaObject); + m_d->parsePythonType(type); + } } -/*! - Returns true if the type is qreal. -*/ -static bool isQRealType(const char *type) +MetaObjectBuilder::~MetaObjectBuilder() { - return strcmp(type, "qreal") == 0; + qDeleteAll(m_d->m_cachedMetaObjects); + delete m_d->m_builder; + delete m_d; } -uint PropertyData::flags() const +int MetaObjectBuilderPrivate::indexOfMethod(QMetaMethod::MethodType mtype, + const QByteArray &signature) const { - const QByteArray btype(type()); - const char* typeName = btype.data(); - uint flags = Invalid; - if (!isVariantType(typeName)) - flags |= EnumOrFlag; - else if (!isQRealType(typeName)) - flags |= qvariant_nameToType(typeName) << 24; - - if (PySide::Property::isReadable(m_data)) - flags |= Readable; - - if (PySide::Property::isWritable(m_data)) - flags |= Writable; - - if (PySide::Property::hasReset(m_data)) - flags |= Resettable; - - if (PySide::Property::isDesignable(m_data)) - flags |= Designable; - else - flags |= ResolveDesignable; - - if (PySide::Property::isScriptable(m_data)) - flags |= Scriptable; - else - flags |= ResolveScriptable; - - if (PySide::Property::isStored(m_data)) - flags |= Stored; - else - flags |= ResolveStored; - - //EDITABLE - flags |= ResolveEditable; - - if (PySide::Property::isUser(m_data)) - flags |= User; - else - flags |= ResolveUser; - - if (m_cachedNotifyId != -1) - flags |= Notify; - - if (PySide::Property::isConstant(m_data)) - flags |= Constant; - - if (PySide::Property::isFinal(m_data)) - flags |= Final; - - return flags; + int result = -1; + if (m_builder) { + switch (mtype) { + case QMetaMethod::Signal: + result = m_builder->indexOfSignal(signature); + break; + case QMetaMethod::Slot: + result = m_builder->indexOfSlot(signature); + break; + case QMetaMethod::Constructor: + result = m_builder->indexOfConstructor(signature); + break; + case QMetaMethod::Method: + result = m_builder->indexOfMethod(signature); + break; + } + if (result >= 0) + return result + m_baseObject->methodCount(); + } + switch (mtype) { + case QMetaMethod::Signal: + result = m_baseObject->indexOfSignal(signature); + break; + case QMetaMethod::Slot: + result = m_baseObject->indexOfSlot(signature); + break; + case QMetaMethod::Constructor: + result = m_baseObject->indexOfConstructor(signature); + break; + case QMetaMethod::Method: + result = m_baseObject->indexOfMethod(signature); + break; + } + return result; } -// const QByteArray with EMPTY_META_METHOD, used to save some memory -const QByteArray MethodData::m_emptySig(EMPTY_META_METHOD); - -MethodData::MethodData() - : m_signature(m_emptySig) +int MetaObjectBuilder::indexOfMethod(QMetaMethod::MethodType mtype, + const QByteArray &signature) const { + return m_d->indexOfMethod(mtype, signature); } -MethodData::MethodData(QMetaMethod::MethodType mtype, const QByteArray& signature, const QByteArray& rtype) - : m_signature(QMetaObject::normalizedSignature(signature.constData())) - , m_rtype(QMetaObject::normalizedSignature(rtype.constData())) - , m_mtype(mtype) +int MetaObjectBuilderPrivate::indexOfProperty(const QByteArray &name) const { + if (m_builder) { + const int result = m_builder->indexOfProperty(name); + if (result >= 0) + return m_baseObject->propertyCount() + result; + } + return m_baseObject->indexOfProperty(name); } -void MethodData::clear() +int MetaObjectBuilder::indexOfProperty(const QByteArray &name) const { - m_signature = m_emptySig; - m_rtype.clear(); + return m_d->indexOfProperty(name); } -bool MethodData::isValid() const +static bool checkMethodSignature(const QByteArray &signature) { - return m_signature != m_emptySig; -} - -QList<QByteArray> MethodData::parameterTypes() const -{ - const char *signature = m_signature.constData(); - QList<QByteArray> list; - while (*signature && *signature != '(') - ++signature; - while (*signature && *signature != ')' && *++signature != ')') { - const char *begin = signature; - int level = 0; - while (*signature && (level > 0 || *signature != ',') && *signature != ')') { - if (*signature == '<') - ++level; - else if (*signature == '>') - --level; - ++signature; - } - list += QByteArray(begin, signature - begin); - } - return list; + // Common mistake not to add parentheses to the signature. + const int openParen = signature.indexOf('('); + const int closingParen = signature.lastIndexOf(')'); + const bool ok = openParen != -1 && closingParen != -1 && openParen < closingParen; + if (!ok) { + const QByteArray message = + "MetaObjectBuilder::addMethod: Invalid method signature provided for \"" + + signature + '"'; + PyErr_WarnEx(PyExc_RuntimeWarning, message.constData(), 0); + } + return ok; } -int MethodData::parameterCount() const +int MetaObjectBuilderPrivate::addSlot(const QByteArray &signature) { - return parameterTypes().size(); + if (!checkMethodSignature(signature)) + return -1; + m_dirty = true; + return m_baseObject->methodCount() + + ensureBuilder()->addSlot(signature).index(); } -QByteArray MethodData::name() const +int MetaObjectBuilder::addSlot(const char *signature) { - return m_signature.left(qMax(m_signature.indexOf('('), 0)); + return m_d->addSlot(signature); } -PropertyData::PropertyData() - : m_cachedNotifyId(0), m_data(0) +int MetaObjectBuilderPrivate::addSlot(const QByteArray &signature, + const QByteArray &type) { + if (!checkMethodSignature(signature)) + return -1; + m_dirty = true; + QMetaMethodBuilder methodBuilder = ensureBuilder()->addSlot(signature); + methodBuilder.setReturnType(type); + return m_baseObject->methodCount() + methodBuilder.index(); } -PropertyData::PropertyData(const char* name, int notifyId, PySideProperty* data) - : m_name(name), m_cachedNotifyId(notifyId), m_data(data) +int MetaObjectBuilder::addSlot(const char *signature, const char *type) { + return m_d->addSlot(signature, type); } -QByteArray PropertyData::type() const +int MetaObjectBuilderPrivate::addSignal(const QByteArray &signature) { - return QByteArray(PySide::Property::getTypeName(m_data)); + if (!checkMethodSignature(signature)) + return -1; + m_dirty = true; + return m_baseObject->methodCount() + + ensureBuilder()->addSignal(signature).index(); } - -bool PropertyData::isValid() const +int MetaObjectBuilder::addSignal(const char *signature) { - return !m_name.isEmpty(); + return m_d->addSignal(signature); } -int PropertyData::cachedNotifyId() const +void MetaObjectBuilderPrivate::removeMethod(QMetaMethod::MethodType mtype, + int index) { - return m_cachedNotifyId; + index -= m_baseObject->methodCount(); + auto builder = ensureBuilder(); + Q_ASSERT(index >= 0 && index < builder->methodCount()); + switch (mtype) { + case QMetaMethod::Constructor: + builder->removeConstructor(index); + break; + default: + builder->removeMethod(index); + break; + } + m_dirty = true; } -bool PropertyData::operator==(const PropertyData& other) const +void MetaObjectBuilder::removeMethod(QMetaMethod::MethodType mtype, int index) { - return m_data == other.m_data; + m_d->removeMethod(mtype, index); } -bool PropertyData::operator==(const char* name) const +int MetaObjectBuilderPrivate::getPropertyNotifyId(PySideProperty *property) const { - return m_name == name; + int notifyId = -1; + if (property->d->notify) { + if (const char *signalNotify = PySide::Property::getNotifyName(property)) + notifyId = indexOfMethod(QMetaMethod::Signal, signalNotify); + } + return notifyId; } - -DynamicQMetaObject::DynamicQMetaObject(PyTypeObject* type, const QMetaObject* base) - : m_d(new DynamicQMetaObjectPrivate) +int MetaObjectBuilderPrivate::addProperty(const QByteArray &propertyName, + PyObject *data) { - d.superdata = base; - d.stringdata = NULL; - d.data = NULL; - d.extradata = NULL; - d.relatedMetaObjects = NULL; - d.static_metacall = NULL; + int index = indexOfProperty(propertyName); + if (index != -1) + return index; - m_d->m_className = QByteArray(type->tp_name).split('.').last(); - m_d->m_methodOffset = base->methodCount() - 1; - m_d->m_propertyOffset = base->propertyCount() - 1; - parsePythonType(type); + PySideProperty *property = reinterpret_cast<PySideProperty *>(data); + int propertyNotifyId = getPropertyNotifyId(property); + if (propertyNotifyId >= 0) + propertyNotifyId -= m_baseObject->methodCount(); + auto newProperty = + ensureBuilder()->addProperty(propertyName, property->d->typeName, + propertyNotifyId); + index = newProperty.index() + m_baseObject->propertyCount(); + m_dirty = true; + return index; } -DynamicQMetaObject::DynamicQMetaObject(const char* className, const QMetaObject* metaObject) - : m_d(new DynamicQMetaObjectPrivate) +int MetaObjectBuilder::addProperty(const char *property, PyObject *data) { - d.superdata = metaObject; - d.stringdata = 0; - d.data = 0; - d.extradata = 0; - d.relatedMetaObjects = NULL; - d.static_metacall = NULL; - - m_d->m_className = className; - m_d->m_methodOffset = metaObject->methodCount() - 1; - m_d->m_propertyOffset = metaObject->propertyCount() - 1; + return m_d->addProperty(property, data); } -DynamicQMetaObject::~DynamicQMetaObject() +void MetaObjectBuilderPrivate::addInfo(const QByteArray &key, + const QByteArray &value) { - free(reinterpret_cast<char *>(const_cast<QByteArrayData *>(d.stringdata))); - free(const_cast<uint*>(d.data)); - delete m_d; + ensureBuilder()->addClassInfo(key, value); + m_dirty = true; } -int DynamicQMetaObject::addMethod(QMetaMethod::MethodType mtype, const char* signature, const char* type) +void MetaObjectBuilder::addInfo(const char *key, const char *value) { - int index = -1; - int counter = 0; - - QList<MethodData>::iterator it = m_d->m_methods.begin(); - for (; it != m_d->m_methods.end(); ++it) { - if ((it->signature() == signature) && (it->methodType() == mtype)) - return m_d->m_methodOffset + counter; - if (!it->isValid()) - index = counter; - counter++; - } - - // Common mistake not to add parentheses to the signature. - if ((strchr(signature, ')') == 0) || ((strchr(signature, '(') == 0))) { - const QString message = - QLatin1String("DynamicQMetaObject::addMethod: Invalid method signature " - "provided for ") + QLatin1String(signature); - const QByteArray messageLatin = message.toLatin1(); - PyErr_WarnEx(PyExc_RuntimeWarning, messageLatin.constData(), 0); - return -1; - } - - //has blank method - if (index != -1) { - m_d->m_methods[index] = MethodData(mtype, signature, type); - index++; - } else { - m_d->m_methods << MethodData(mtype, signature, type); - index = m_d->m_methods.size(); - } - - m_d->m_updated = false; - return m_d->m_methodOffset + index; + m_d->addInfo(key, value); } -void DynamicQMetaObject::removeMethod(QMetaMethod::MethodType mtype, uint index) +void MetaObjectBuilderPrivate::addInfo(const QMap<QByteArray, QByteArray> &info) { - const char* methodSig = method(index).methodSignature(); - QList<MethodData>::iterator it = m_d->m_methods.begin(); - for (; it != m_d->m_methods.end(); ++it) { - if ((it->signature() == methodSig) && (it->methodType() == mtype)){ - it->clear(); - m_d->m_updated = false; - break; - } - } + auto builder = ensureBuilder(); + for (auto i = info.constBegin(), end = info.constEnd(); i != end; ++i) + builder->addClassInfo(i.key(), i.value()); + m_dirty = true; } -int DynamicQMetaObject::addSignal(const char* signal, const char* type) +void MetaObjectBuilder::addInfo(const QMap<QByteArray, QByteArray> &info) { - return addMethod(QMetaMethod::Signal, signal, type); + m_d->addInfo(info); } -int DynamicQMetaObject::addSlot(const char* slot, const char* type) +void MetaObjectBuilderPrivate::removeProperty(int index) { - return addMethod(QMetaMethod::Slot, slot, type); + index -= m_baseObject->propertyCount(); + auto builder = ensureBuilder(); + Q_ASSERT(index >= 0 && index < builder->propertyCount()); + builder->removeProperty(index); + m_dirty = true; } -void DynamicQMetaObject::removeSlot(uint index) +void MetaObjectBuilder::removeProperty(int index) { - removeMethod(QMetaMethod::Slot, index); + m_d->removeProperty(index); } -void DynamicQMetaObject::removeSignal(uint index) -{ - removeMethod(QMetaMethod::Signal, index); -} +// PYSIDE-315: Instead of sorting the items and maybe breaking indices, we +// ensure that the signals and slots are sorted by the improved +// parsePythonType() (signals must go before slots). The order can only +// become distorted if the class is modified after creation. In that +// case, we give a warning. -int DynamicQMetaObject::addProperty(const char* propertyName, PyObject* data) +static QString msgMethodSortOrder(const QMetaObject *mo, int offendingIndex) { - int index = m_d->m_properties.indexOf(propertyName); - if (index != -1) - return m_d->m_propertyOffset + index; - - // retrieve notifyId - PySideProperty *property = reinterpret_cast<PySideProperty *>(data); - const int notifyId = m_d->getPropertyNotifyId(property); - - //search for a empty space - PropertyData blank; - index = m_d->m_properties.indexOf(blank); - if (index != -1) { - m_d->m_properties[index] = PropertyData(propertyName, notifyId, property); - } else { - m_d->m_properties << PropertyData(propertyName, notifyId, property); - index = m_d->m_properties.size(); + QString result; + QTextStream str(&result); + str << "\n\n*** Sort Warning ***\nSignals and slots in QMetaObject '" + << mo->className() + << "' are not ordered correctly, this may lead to issues.\n"; + const int methodOffset = mo->methodOffset(); + for (int m = methodOffset, methodCount = mo->methodCount(); m < methodCount; ++m) { + const auto method = mo->method(m); + str << (m - methodOffset + 1) << (m > offendingIndex ? '!' : ' ') + << (method.methodType() == QMetaMethod::Signal ? " Signal " : " Slot ") + << method.methodSignature() << '\n'; } - m_d->m_updated = false; - return m_d->m_propertyOffset + index; + return result; } -int DynamicQMetaObject::DynamicQMetaObjectPrivate::getPropertyNotifyId(PySideProperty *property) const +static void checkMethodOrder(const QMetaObject *metaObject) { - int notifyId = -1; - if (property->d->notify) { - const char *signalNotify = PySide::Property::getNotifyName(property); - if (signalNotify) { - const MethodData signalObject(QMetaMethod::Signal, signalNotify, ""); - notifyId = m_methods.indexOf(signalObject); + const int lastMethod = metaObject->methodCount() - 1; + for (int m = metaObject->methodOffset(); m < lastMethod; ++m) { + if (metaObject->method(m).methodType() == QMetaMethod::Slot + && metaObject->method(m + 1).methodType() == QMetaMethod::Signal) { + const auto message = msgMethodSortOrder(metaObject, m); + PyErr_WarnEx(PyExc_RuntimeWarning, qPrintable(message), 0); + // Prevent a warning from being turned into an error. We cannot easily unwind. + PyErr_Clear(); + break; } } - return notifyId; -} - -void DynamicQMetaObject::addInfo(const char* key, const char* value) -{ - m_d->m_info[key] = value; -} - -void DynamicQMetaObject::addInfo(const QMap<QByteArray, QByteArray> &info) -{ - QMap<QByteArray, QByteArray>::const_iterator i = info.constBegin(); - while (i != info.constEnd()) { - m_d->m_info[i.key()] = i.value(); - ++i; - } - m_d->m_updated = false; } -const QMetaObject* DynamicQMetaObject::update() const +const QMetaObject *MetaObjectBuilderPrivate::update() { - if (!m_d->m_updated) { - m_d->updateMetaObject(const_cast<DynamicQMetaObject*>(this)); - m_d->m_updated = true; + if (!m_builder) + return m_baseObject; + if (m_cachedMetaObjects.empty() || m_dirty) { + m_cachedMetaObjects.push_back(m_builder->toMetaObject()); + checkMethodOrder(m_cachedMetaObjects.back()); + m_dirty = false; } - return this; + return m_cachedMetaObjects.back(); } -void DynamicQMetaObject::DynamicQMetaObjectPrivate::writeMethodsData(const QList<MethodData>& methods, - unsigned int** data, - QByteArrayList& strings, - int* prtIndex, - int nullIndex, - int flags) +const QMetaObject *MetaObjectBuilder::update() { - int index = *prtIndex; - int paramsIndex = index + methods.count() * 5; - - QList<MethodData>::const_iterator it = methods.begin(); - - if (m_emptyMethod == -1) - m_emptyMethod = registerString(EMPTY_META_METHOD, strings); - - for (; it != methods.end(); ++it) { - int name_idx = 0; - int argc = it->parameterCount(); - if (it->signature() != EMPTY_META_METHOD) - name_idx = registerString(it->name(), strings); - else - name_idx = m_emptyMethod; // func name - - (*data)[index++] = name_idx; - (*data)[index++] = argc; // argc (previously: arg name) - (*data)[index++] = paramsIndex; //parameter index - (*data)[index++] = nullIndex; // tags - (*data)[index++] = flags | (it->methodType() == QMetaMethod::Signal ? MethodSignal : MethodSlot); - - if (it->methodType() == QMetaMethod::Signal) - (*data)[13] += 1; //signal count - - paramsIndex += 1 + argc * 2; - } - *prtIndex = index; + return m_d->update(); } -void DynamicQMetaObject::parsePythonType(PyTypeObject *type) +void MetaObjectBuilderPrivate::parsePythonType(PyTypeObject *type) { // Get all non-QObject-derived base types in method resolution order, filtering out the types // that can't have signals, slots or properties. @@ -609,8 +459,8 @@ void DynamicQMetaObject::parsePythonType(PyTypeObject *type) if (data->signatures[i]) sig += data->signatures[i]; sig += ')'; - if (d.superdata->indexOfSignal(sig) == -1) - addSignal(sig, "void"); + if (m_baseObject->indexOfSignal(sig) == -1) + m_builder->addSignal(sig); } } } @@ -634,7 +484,7 @@ void DynamicQMetaObject::parsePythonType(PyTypeObject *type) if (Property::checkType(value)) { // Leave the properties to be registered after signals because they may depend on // notify signals. - int index = d.superdata->indexOfProperty(Shiboken::String::toCString(key)); + int index = m_baseObject->indexOfProperty(Shiboken::String::toCString(key)); if (index == -1) properties << PropPair(Shiboken::String::toCString(key), value); } else if (PyFunction_Check(value)) { @@ -642,13 +492,23 @@ void DynamicQMetaObject::parsePythonType(PyTypeObject *type) if (PyObject_HasAttr(value, slotAttrName)) { PyObject *signatureList = PyObject_GetAttr(value, slotAttrName); for (Py_ssize_t i = 0, i_max = PyList_Size(signatureList); i < i_max; ++i) { - PyObject *signature = PyList_GET_ITEM(signatureList, i); - QByteArray sig(Shiboken::String::toCString(signature)); + PyObject *pySignature = PyList_GET_ITEM(signatureList, i); + QByteArray signature(Shiboken::String::toCString(pySignature)); // Split the slot type and its signature. - QList<QByteArray> slotInfo = sig.split(' '); - int index = d.superdata->indexOfSlot(slotInfo[1]); - if (index == -1) - addSlot(slotInfo[1], slotInfo[0]); + QByteArray type; + const int spacePos = signature.indexOf(' '); + if (spacePos != -1) { + type = signature.left(spacePos); + signature.remove(0, spacePos + 1); + } + int index = m_baseObject->indexOfSlot(signature); + if (index == -1) { + if (type.isEmpty() || type == "void") { + addSlot(signature); + } else { + addSlot(signature, type); + } + } } } } @@ -659,219 +519,3 @@ void DynamicQMetaObject::parsePythonType(PyTypeObject *type) addProperty(propPair.first, propPair.second); } } - -/*! - Allocate the meta data table. - Returns the index in the table corresponding to the header fields count. -*/ -int DynamicQMetaObject::DynamicQMetaObjectPrivate::createMetaData(QMetaObject* metaObj) -{ - const int n_methods = m_methods.size(); - const int n_properties = m_properties.size(); - const int n_info = m_info.size(); - - int header[] = {7, // revision (Used by moc, qmetaobjectbuilder and qdbus) - 0, // class name index in m_metadata - n_info, 0, // classinfo and classinfo index - n_methods, 0, // method count and method list index - n_properties, 0, // prop count and prop indexes - 0, 0, // enum count and enum index - 0, 0, // constructors (since revision 2) - 0, // flags (since revision 3) - 0}; // signal count (since revision 4) - - const int HEADER_LENGHT = sizeof(header)/sizeof(int); - - m_dataSize = HEADER_LENGHT; - m_dataSize += n_info*2; //class info: name, value - m_dataSize += n_methods*5; //method: name, argc, parameters, tag, flags - m_dataSize += n_properties*4; //property: name, type, flags - m_dataSize += 1; //eod - - m_dataSize += aggregateParameterCount(m_methods); // types and parameter names - - uint* data = reinterpret_cast<uint*>(realloc(const_cast<uint*>(metaObj->d.data), m_dataSize * sizeof(uint))); - - Q_ASSERT(data); - std::memcpy(data, header, sizeof(header)); - - metaObj->d.data = data; - - return HEADER_LENGHT; -} - -// Writes strings to string data struct. -// The struct consists of an array of QByteArrayData, followed by a char array -// containing the actual strings. This format must match the one produced by -// moc (see generator.cpp). -void DynamicQMetaObject::DynamicQMetaObjectPrivate::writeStringData(char *out, - const QByteArrayList& strings) const -{ - Q_ASSERT(!(reinterpret_cast<quintptr>(out) & (Q_ALIGNOF(QByteArrayData)-1))); - - const int size = strings.size(); - const int offsetOfStringdataMember = size * int(sizeof(QByteArrayData)); - int stringdataOffset = 0; - for (int i = 0; i < size; ++i) - writeString(out, i, strings.at(i), offsetOfStringdataMember, stringdataOffset); -} - -QList<MethodData>::iterator is_sorted_until(QList<MethodData>::iterator first, - QList<MethodData>::iterator last, - bool comp(const MethodData &m1, const MethodData &m2)) -{ - if (first != last) { - QList<MethodData>::iterator next = first; - while (++next != last) { - if (comp(*next, *first)) - return next; - ++first; - } - } - return last; -} - -bool is_sorted(QList<MethodData>::iterator first, QList<MethodData>::iterator last, - bool comp(const MethodData &m1, const MethodData &m2)) -{ - return is_sorted_until(first, last, comp) == last; -} - -void DynamicQMetaObject::DynamicQMetaObjectPrivate::updateMetaObject(QMetaObject* metaObj) -{ - Q_ASSERT(!m_updated); - m_dataSize = 0; - - // Recompute the size and reallocate memory - // index is set after the last header field. - int index = createMetaData(metaObj); - uint *data = const_cast<uint*>(metaObj->d.data); - - QByteArrayList strings; - strings.append(m_className); // register class string - m_nullIndex = registerString(QByteArrayLiteral(""), strings); // register a null string - - // Write class info. - if (!m_info.isEmpty()) { - if (data[3] == 0) - data[3] = index; - - QMap<QByteArray, QByteArray>::const_iterator i = m_info.constBegin(); //TODO: info is a hash this can fail - while (i != m_info.constEnd()) { - int valueIndex = registerString(i.value(), strings); - int keyIndex = registerString(i.key(), strings); - data[index++] = keyIndex; - data[index++] = valueIndex; - i++; - } - } - - // Write methods first, then properties, to be consistent with moc. - // Write signals/slots (signals must be written first, see indexOfMethodRelative in - // qmetaobject.cpp). - - QList<MethodData>::iterator it; - // PYSIDE-315: Instead of sorting the items and maybe breaking indices, - // we ensure that the signals and slots are sorted by the improved parsePythonType(). - // The order can only become distorted if the class is modified after creation. - // In that case, we give a warning. - if (!is_sorted(m_methods.begin(), m_methods.end(), sortMethodSignalSlot)) { - const char *metaObjectName = this->m_className.data(); - PyObject *txt = PyBytes_FromFormat("\n\n*** Sort Warning ***\n" - "Signals and slots in QMetaObject '%s' are not ordered correctly, " - "this may lead to issues.\n", metaObjectName); - it = m_methods.begin(); - QList<MethodData>::iterator end = m_methods.end(); - QList<MethodData>::iterator until = is_sorted_until(m_methods.begin(), m_methods.end(), - sortMethodSignalSlot); - for (; it != end; ++it) { - PyObject *atxt = PyBytes_FromFormat("%d%s %s %s\n", it - m_methods.begin() + 1, - until >= it + 1 ? " " : "!", - it->methodType() == QMetaMethod::Signal ? "Signal" : "Slot ", - it->signature().data() ); - PyBytes_ConcatAndDel(&txt, atxt); - } - PyErr_WarnEx(PyExc_RuntimeWarning, PyBytes_AsString(txt), 0); - Py_DECREF(txt); - // Prevent a warning from being turned into an error. We cannot easily unwind. - PyErr_Clear(); - } - - if (!m_methods.empty()) { - if (data[5] == 0) - data[5] = index; - - writeMethodsData(m_methods, &data, strings, &index, m_nullIndex, AccessPublic); - } - - // Write signal/slots parameters. - if (!m_methods.empty()) { - for (it = m_methods.begin(); it != m_methods.end(); ++it) { - QList<QByteArray> paramTypeNames = it->parameterTypes(); - int paramCount = paramTypeNames.size(); - for (int i = -1; i < paramCount; ++i) { - const QByteArray &typeName = (i < 0) ? it->returnType() : paramTypeNames.at(i); - int typeInfo; - if (QtPrivate::isBuiltinType(typeName)) - typeInfo = QMetaType::type(typeName); - else - typeInfo = IsUnresolvedType | registerString(typeName, strings); - data[index++] = typeInfo; - } - - // Parameter names (use a null string) - for (int i = 0; i < paramCount; ++i) { - data[index++] = m_nullIndex; - } - } - } - - // Write properties. - if (m_properties.size()) { - if (data[7] == 0) - data[7] = index; - - QList<PropertyData>::const_iterator i = m_properties.constBegin(); - while (i != m_properties.constEnd()) { - if (i->isValid()) { - data[index++] = registerString(i->name(), strings); // name - } else - data[index++] = m_nullIndex; - - // Find out the property type index. - int typeInfo = m_nullIndex; - if (i->isValid()) { - const QByteArray &typeName = i->type(); - if (QtPrivate::isBuiltinType(typeName)) - typeInfo = QMetaType::type(typeName); - else - typeInfo = IsUnresolvedType | registerString(typeName, strings); - } - data[index++] = typeInfo; // normalized type - - data[index++] = i->flags(); - i++; - } - - // Write properties notify. - i = m_properties.constBegin(); - while (i != m_properties.constEnd()) { - // Recompute notifyId, because sorting the methods might have changed the relative - // index. - const int notifyId = getPropertyNotifyId(i->data()); - data[index++] = notifyId >= 0 ? static_cast<uint>(notifyId) : 0; //signal notify index - i++; - } - } - - data[index++] = 0; // the end - - // Create the m_metadata string. - int size = blobSize(strings); - char *blob = - reinterpret_cast<char *>(realloc(reinterpret_cast<char *>(const_cast<QByteArrayData *>(metaObj->d.stringdata)), size)); - writeStringData(blob, strings); - - metaObj->d.stringdata = reinterpret_cast<const QByteArrayData *>(blob); - metaObj->d.data = data; -} diff --git a/sources/pyside2/libpyside/dynamicqmetaobject.h b/sources/pyside2/libpyside/dynamicqmetaobject.h index e68c7dd50..1fbe73ea4 100644 --- a/sources/pyside2/libpyside/dynamicqmetaobject.h +++ b/sources/pyside2/libpyside/dynamicqmetaobject.h @@ -45,39 +45,37 @@ #include <QtCore/QMetaObject> #include <QtCore/QMetaMethod> +class MetaObjectBuilderPrivate; + namespace PySide { -class DynamicQMetaObject : public QMetaObject +class MetaObjectBuilder { - Q_DISABLE_COPY(DynamicQMetaObject) + Q_DISABLE_COPY(MetaObjectBuilder) public: - DynamicQMetaObject(const char* className, const QMetaObject* metaObject); - DynamicQMetaObject(PyTypeObject* type, const QMetaObject* metaobject); - ~DynamicQMetaObject(); + MetaObjectBuilder(const char *className, const QMetaObject *metaObject); + MetaObjectBuilder(PyTypeObject *type, const QMetaObject *metaObject); + ~MetaObjectBuilder(); - int addMethod(QMetaMethod::MethodType mtype, const char* signature, const char* type); - void removeMethod(QMetaMethod::MethodType mtype, uint index); - int addSignal(const char* signal, const char* type = 0); - int addSlot(const char* slot, const char* type = 0); - int addProperty(const char* property, PyObject* data); - void addInfo(const char* key, const char* value); + int indexOfMethod(QMetaMethod::MethodType mtype, const QByteArray &signature) const; + int indexOfProperty(const QByteArray &name) const; + int addSlot(const char *signature); + int addSlot(const char *signature, const char *type); + int addSignal(const char *signature); + void removeMethod(QMetaMethod::MethodType mtype, int index); + int addProperty(const char *property, PyObject *data); + void addInfo(const char *key, const char *value); void addInfo(const QMap<QByteArray, QByteArray> &info); - void removeSignal(uint idex); - void removeSlot(uint index); - void removeProperty(uint index); + void removeProperty(int index); - const QMetaObject* update() const; + const QMetaObject *update(); private: - class DynamicQMetaObjectPrivate; - DynamicQMetaObjectPrivate* m_d; - - void parsePythonType(PyTypeObject *type); + MetaObjectBuilderPrivate *m_d; }; - } #endif diff --git a/sources/pyside2/libpyside/globalreceiverv2.cpp b/sources/pyside2/libpyside/globalreceiverv2.cpp index a1a695759..43ce50a75 100644 --- a/sources/pyside2/libpyside/globalreceiverv2.cpp +++ b/sources/pyside2/libpyside/globalreceiverv2.cpp @@ -160,10 +160,8 @@ int DynamicSlotDataV2::id(const char* signature) const int DynamicSlotDataV2::addSlot(const char* signature) { int index = id(signature); - if (index == -1) { - DynamicQMetaObject *dmo = const_cast<DynamicQMetaObject*>(reinterpret_cast<const DynamicQMetaObject*>(m_parent->metaObject())); - index = m_signatures[signature] = dmo->addSlot(signature); - } + if (index == -1) + index = m_signatures[signature] = m_parent->metaObjectBuilder().addSlot(signature); return index; } @@ -202,7 +200,7 @@ GlobalReceiverV2::GlobalReceiverV2(PyObject *callback, SharedMap map) : DESTROY_SIGNAL_ID = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)"); if (DESTROY_SLOT_ID == 0) - DESTROY_SLOT_ID = m_metaObject.indexOfSlot(RECEIVER_DESTROYED_SLOT_NAME); + DESTROY_SLOT_ID = m_metaObject.indexOfMethod(QMetaMethod::Slot, RECEIVER_DESTROYED_SLOT_NAME); } @@ -306,7 +304,7 @@ QByteArray GlobalReceiverV2::hash(PyObject* callback) const QMetaObject* GlobalReceiverV2::metaObject() const { - return m_metaObject.update(); + return const_cast<GlobalReceiverV2 *>(this)->m_metaObject.update(); } int GlobalReceiverV2::qt_metacall(QMetaObject::Call call, int id, void** args) diff --git a/sources/pyside2/libpyside/globalreceiverv2.h b/sources/pyside2/libpyside/globalreceiverv2.h index b12823a84..b92be93a8 100644 --- a/sources/pyside2/libpyside/globalreceiverv2.h +++ b/sources/pyside2/libpyside/globalreceiverv2.h @@ -135,8 +135,11 @@ public: **/ static QByteArray hash(PyObject* callback); + const MetaObjectBuilder &metaObjectBuilder() const { return m_metaObject; } + MetaObjectBuilder &metaObjectBuilder() { return m_metaObject; } + private: - DynamicQMetaObject m_metaObject; + MetaObjectBuilder m_metaObject; DynamicSlotDataV2 *m_data; QList<const QObject*> m_refs; SharedMap m_sharedMap; diff --git a/sources/pyside2/libpyside/pyside.cpp b/sources/pyside2/libpyside/pyside.cpp index 856e5b92c..6e4a3efd4 100644 --- a/sources/pyside2/libpyside/pyside.cpp +++ b/sources/pyside2/libpyside/pyside.cpp @@ -204,7 +204,7 @@ void initDynamicMetaObject(SbkObjectType* type, const QMetaObject* base, std::si Shiboken::ObjectType::setTypeUserData(type, userData, Shiboken::callCppDestructor<TypeUserData>); //initialize staticQMetaObject property - void* metaObjectPtr = &userData->mo; + void *metaObjectPtr = const_cast<QMetaObject *>(userData->mo.update()); static SbkConverter* converter = Shiboken::Conversions::getConverter("QMetaObject"); if (!converter) return; @@ -229,13 +229,13 @@ TypeUserData *retrieveTypeUserData(PyObject *pyObj) return retrieveTypeUserData(pyTypeObj); } -DynamicQMetaObject *retrieveMetaObject(PyTypeObject *pyTypeObj) +const QMetaObject *retrieveMetaObject(PyTypeObject *pyTypeObj) { TypeUserData *userData = retrieveTypeUserData(pyTypeObj); - return userData ? &(userData->mo) : nullptr; + return userData ? userData->mo.update() : nullptr; } -DynamicQMetaObject *retrieveMetaObject(PyObject *pyObj) +const QMetaObject *retrieveMetaObject(PyObject *pyObj) { auto pyTypeObj = PyType_Check(pyObj) ? reinterpret_cast<PyTypeObject *>(pyObj) : Py_TYPE(pyObj); @@ -268,8 +268,7 @@ void initQObjectSubType(SbkObjectType *type, PyObject *args, PyObject * /* kwds qWarning("Sub class of QObject not inheriting QObject!? Crash will happen when using %s.", className.constData()); return; } - userData->mo.update(); - initDynamicMetaObject(type, &userData->mo, userData->cppObjSize); + initDynamicMetaObject(type, userData->mo.update(), userData->cppObjSize); } PyObject* getMetaDataFromQObject(QObject* cppSelf, PyObject* self, PyObject* name) diff --git a/sources/pyside2/libpyside/pyside_p.h b/sources/pyside2/libpyside/pyside_p.h index 66a37fc7a..1084a40a1 100644 --- a/sources/pyside2/libpyside/pyside_p.h +++ b/sources/pyside2/libpyside/pyside_p.h @@ -55,7 +55,7 @@ struct TypeUserData explicit TypeUserData(PyTypeObject* type, const QMetaObject* metaobject, std::size_t size) : mo(type, metaobject), cppObjSize(size) {} - DynamicQMetaObject mo; + MetaObjectBuilder mo; std::size_t cppObjSize; }; @@ -63,8 +63,8 @@ TypeUserData *retrieveTypeUserData(SbkObjectType *sbkTypeObj); TypeUserData *retrieveTypeUserData(PyTypeObject *pyTypeObj); TypeUserData *retrieveTypeUserData(PyObject *pyObj); // For QML -PYSIDE_API DynamicQMetaObject *retrieveMetaObject(PyTypeObject *pyTypeObj); -PYSIDE_API DynamicQMetaObject *retrieveMetaObject(PyObject *pyObj); +PYSIDE_API const QMetaObject *retrieveMetaObject(PyTypeObject *pyTypeObj); +PYSIDE_API const QMetaObject *retrieveMetaObject(PyObject *pyObj); } //namespace PySide diff --git a/sources/pyside2/libpyside/pysideclassinfo.cpp b/sources/pyside2/libpyside/pysideclassinfo.cpp index 88b2b89f5..4edf0fa91 100644 --- a/sources/pyside2/libpyside/pysideclassinfo.cpp +++ b/sources/pyside2/libpyside/pysideclassinfo.cpp @@ -61,7 +61,7 @@ static PyType_Slot PySideClassInfoType_slots[] = { {Py_tp_init, (void *)classInfoTpInit}, {Py_tp_new, (void *)classInfoTpNew}, {Py_tp_free, (void *)classInfoFree}, - {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {Py_tp_dealloc, (void *)object_dealloc}, {0, 0} }; static PyType_Spec PySideClassInfoType_spec = { @@ -108,8 +108,9 @@ PyObject *classCall(PyObject *self, PyObject *args, PyObject * /* kw */) PyTypeObject *klassType = reinterpret_cast<PyTypeObject*>(klass); if (Shiboken::ObjectType::checkType(klassType)) { - if (PySide::DynamicQMetaObject *mo = PySide::retrieveMetaObject(klassType)) { - mo->addInfo(PySide::ClassInfo::getMap(data)); + if (auto userData = PySide::retrieveTypeUserData(klassType)) { + PySide::MetaObjectBuilder &mo = userData->mo; + mo.addInfo(PySide::ClassInfo::getMap(data)); pData->m_alreadyWrapped = true; validClass = true; } diff --git a/sources/pyside2/libpyside/pysidemetafunction.cpp b/sources/pyside2/libpyside/pysidemetafunction.cpp index 80496764d..4cdc7ec16 100644 --- a/sources/pyside2/libpyside/pysidemetafunction.cpp +++ b/sources/pyside2/libpyside/pysidemetafunction.cpp @@ -61,7 +61,7 @@ static PyType_Slot PySideMetaFunctionType_slots[] = { {Py_tp_call, (void *)functionCall}, {Py_tp_new, (void *)PyType_GenericNew}, {Py_tp_free, (void *)functionFree}, - {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {Py_tp_dealloc, (void *)object_dealloc}, {0, 0} }; static PyType_Spec PySideMetaFunctionType_spec = { diff --git a/sources/pyside2/libpyside/pysideqflags.cpp b/sources/pyside2/libpyside/pysideqflags.cpp index f948ecac7..cb57031b0 100644 --- a/sources/pyside2/libpyside/pysideqflags.cpp +++ b/sources/pyside2/libpyside/pysideqflags.cpp @@ -152,7 +152,7 @@ namespace QFlags #endif {Py_tp_new, (void *)PySideQFlagsNew}, {Py_tp_richcompare, (void *)PySideQFlagsRichCompare}, - {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {Py_tp_dealloc, (void *)object_dealloc}, {0, 0} }; static PyType_Spec SbkNewQFlagsType_spec = { diff --git a/sources/pyside2/libpyside/pysidesignal.cpp b/sources/pyside2/libpyside/pysidesignal.cpp index 3b21b16da..e7fd389a8 100644 --- a/sources/pyside2/libpyside/pysidesignal.cpp +++ b/sources/pyside2/libpyside/pysidesignal.cpp @@ -109,7 +109,7 @@ static PyType_Slot PySideSignalMetaType_slots[] = { {Py_tp_methods, (void *)Signal_methods}, {Py_tp_base, (void *)&PyType_Type}, {Py_tp_free, (void *)PyObject_GC_Del}, - {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {Py_tp_dealloc, (void *)object_dealloc}, {0, 0} }; static PyType_Spec PySideSignalMetaType_spec = { @@ -141,7 +141,7 @@ static PyType_Slot PySideSignalType_slots[] = { {Py_tp_init, (void *)signalTpInit}, {Py_tp_new, (void *)PyType_GenericNew}, {Py_tp_free, (void *)signalFree}, - {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {Py_tp_dealloc, (void *)object_dealloc}, {0, 0} }; static PyType_Spec PySideSignalType_spec = { @@ -180,7 +180,7 @@ static PyType_Slot PySideSignalInstanceType_slots[] = { {Py_tp_methods, (void *)SignalInstance_methods}, {Py_tp_new, (void *)PyType_GenericNew}, {Py_tp_free, (void *)signalInstanceFree}, - {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {Py_tp_dealloc, (void *)object_dealloc}, {0, 0} }; static PyType_Spec PySideSignalInstanceType_spec = { diff --git a/sources/pyside2/libpyside/pysideslot.cpp b/sources/pyside2/libpyside/pysideslot.cpp index 0dff3bafb..6f6658cf8 100644 --- a/sources/pyside2/libpyside/pysideslot.cpp +++ b/sources/pyside2/libpyside/pysideslot.cpp @@ -67,7 +67,7 @@ static PyType_Slot PySideSlotType_slots[] = { {Py_tp_call, (void *)slotCall}, {Py_tp_init, (void *)slotTpInit}, {Py_tp_new, (void *)PyType_GenericNew}, - {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {Py_tp_dealloc, (void *)object_dealloc}, {0, 0} }; static PyType_Spec PySideSlotType_spec = { diff --git a/sources/pyside2/libpyside/pysideweakref.cpp b/sources/pyside2/libpyside/pysideweakref.cpp index a0b7f4aaa..6b5073db8 100644 --- a/sources/pyside2/libpyside/pysideweakref.cpp +++ b/sources/pyside2/libpyside/pysideweakref.cpp @@ -53,7 +53,7 @@ static PyObject* CallableObject_call(PyObject* callable_object, PyObject* args, static PyType_Slot PySideCallableObjectType_slots[] = { {Py_tp_call, (void *)CallableObject_call}, - {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {Py_tp_dealloc, (void *)object_dealloc}, {0, 0} }; static PyType_Spec PySideCallableObjectType_spec = { diff --git a/sources/pyside2/libpyside/signalmanager.cpp b/sources/pyside2/libpyside/signalmanager.cpp index f505fde5a..8925ffd35 100644 --- a/sources/pyside2/libpyside/signalmanager.cpp +++ b/sources/pyside2/libpyside/signalmanager.cpp @@ -90,7 +90,7 @@ namespace { static void destroyMetaObject(PyObject* obj) { void* ptr = PyCapsule_GetPointer(obj, 0); - PySide::DynamicQMetaObject* meta = reinterpret_cast<PySide::DynamicQMetaObject*>(ptr); + auto meta = reinterpret_cast<PySide::MetaObjectBuilder*>(ptr); SbkObject* wrapper = Shiboken::BindingManager::instance().retrieveWrapper(meta); if (wrapper) Shiboken::BindingManager::instance().releaseWrapper(wrapper); @@ -100,7 +100,7 @@ namespace { #else static void destroyMetaObject(void* obj) { - PySide::DynamicQMetaObject* meta = reinterpret_cast<PySide::DynamicQMetaObject*>(obj); + auto meta = reinterpret_cast<PySide::MetaObjectBuilder*>(obj); SbkObject* wrapper = Shiboken::BindingManager::instance().retrieveWrapper(meta); if (wrapper) Shiboken::BindingManager::instance().releaseWrapper(wrapper); @@ -549,6 +549,19 @@ bool SignalManager::registerMetaMethod(QObject* source, const char* signature, Q return (ret != -1); } +static MetaObjectBuilder *metaBuilderFromDict(PyObject* dict) +{ + if (!dict || !PyDict_Contains(dict, metaObjectAttr)) + return nullptr; + + PyObject *pyBuilder = PyDict_GetItem(dict, metaObjectAttr); +#ifdef IS_PY3K + return reinterpret_cast<MetaObjectBuilder *>(PyCapsule_GetPointer(pyBuilder, nullptr)); +#else + return reinterpret_cast<MetaObjectBuilder *>(PyCObject_AsVoidPtr(pyBuilder)); +#endif +} + int SignalManager::registerMetaMethodGetIndex(QObject* source, const char* signature, QMetaMethod::MethodType type) { if (!source) { @@ -565,13 +578,13 @@ int SignalManager::registerMetaMethodGetIndex(QObject* source, const char* signa qWarning() << "Invalid Signal signature:" << signature; return -1; } else { - DynamicQMetaObject *dmo = 0; PyObject *pySelf = reinterpret_cast<PyObject*>(self); PyObject* dict = self->ob_dict; + MetaObjectBuilder *dmo = metaBuilderFromDict(dict); // Create a instance meta object - if (!dict || !PyDict_Contains(dict, metaObjectAttr)) { - dmo = new DynamicQMetaObject(Py_TYPE(pySelf), metaObject); + if (!dmo) { + dmo = new MetaObjectBuilder(Py_TYPE(pySelf), metaObject); #ifdef IS_PY3K PyObject* pyDmo = PyCapsule_New(dmo, 0, destroyMetaObject); #else @@ -580,8 +593,6 @@ int SignalManager::registerMetaMethodGetIndex(QObject* source, const char* signa PyObject_SetAttr(pySelf, metaObjectAttr, pyDmo); Py_DECREF(pyDmo); - } else { - dmo = reinterpret_cast<DynamicQMetaObject*>(const_cast<QMetaObject*>(metaObject)); } if (type == QMetaMethod::Signal) @@ -596,24 +607,13 @@ int SignalManager::registerMetaMethodGetIndex(QObject* source, const char* signa const QMetaObject* SignalManager::retrieveMetaObject(PyObject *self) { Shiboken::GilState gil; - DynamicQMetaObject *mo = 0; Q_ASSERT(self); - PyObject* dict = reinterpret_cast<SbkObject*>(self)->ob_dict; - if (dict && PyDict_Contains(dict, metaObjectAttr)) { - PyObject *pyMo = PyDict_GetItem(dict, metaObjectAttr); - -#ifdef IS_PY3K - mo = reinterpret_cast<DynamicQMetaObject*>(PyCapsule_GetPointer(pyMo, 0)); -#else - mo = reinterpret_cast<DynamicQMetaObject*>(PyCObject_AsVoidPtr(pyMo)); -#endif - } else { - mo = PySide::retrieveMetaObject(self); - } + MetaObjectBuilder *builder = metaBuilderFromDict(reinterpret_cast<SbkObject*>(self)->ob_dict); + if (!builder) + builder = &(retrieveTypeUserData(self)->mo); - mo->update(); - return mo; + return builder->update(); } namespace { diff --git a/sources/pyside2/tests/QtCore/qmetaobject_test.py b/sources/pyside2/tests/QtCore/qmetaobject_test.py index 12b5312a6..73ab81c7c 100644 --- a/sources/pyside2/tests/QtCore/qmetaobject_test.py +++ b/sources/pyside2/tests/QtCore/qmetaobject_test.py @@ -78,6 +78,12 @@ class qmetaobject_test(unittest.TestCase): #self.assertTrue(slot_index != signal_index) + # PYSIDE-784, plain Qt objects should not have intermediary + # metaObjects. + def test_PlainQObject(self): + timer = QTimer() + self.assertEqual(timer.metaObject().superClass().className(), + "QObject") if __name__ == '__main__': unittest.main() diff --git a/sources/pyside2/tests/QtWidgets/qwidget_test.py b/sources/pyside2/tests/QtWidgets/qwidget_test.py index 1e8387d11..028751ba7 100644 --- a/sources/pyside2/tests/QtWidgets/qwidget_test.py +++ b/sources/pyside2/tests/QtWidgets/qwidget_test.py @@ -26,6 +26,7 @@ ## ############################################################################# +import sys import unittest from PySide2.QtWidgets import QWidget, QMainWindow @@ -35,6 +36,17 @@ class QWidgetInherit(QMainWindow): def __init__(self): QWidget.__init__(self) +class NativeEventTestWidget(QWidget): + + nativeEventCount = 0 + + def __init__(self): + QWidget.__init__(self) + + def nativeEvent(self, eventType, message): + self.nativeEventCount = self.nativeEventCount + 1 + return [False, 0] + class QWidgetTest(UsesQApplication): def testInheritance(self): @@ -44,12 +56,19 @@ class QWidgetVisible(UsesQApplication): def testBasic(self): # Also related to bug #244, on existence of setVisible''' - widget = QWidget() + widget = NativeEventTestWidget() self.assertTrue(not widget.isVisible()) widget.setVisible(True) self.assertTrue(widget.isVisible()) self.assertTrue(widget.winId() is not 0) - + # skip this test on macOS since no native events are received + if sys.platform == 'darwin': + return + for i in range(10): + if widget.nativeEventCount > 0: + break + self.app.processEvents() + self.assertTrue(widget.nativeEventCount > 0) if __name__ == '__main__': unittest.main() diff --git a/sources/pyside2/tests/pysidetest/CMakeLists.txt b/sources/pyside2/tests/pysidetest/CMakeLists.txt index 5b7f0fde1..119553fad 100644 --- a/sources/pyside2/tests/pysidetest/CMakeLists.txt +++ b/sources/pyside2/tests/pysidetest/CMakeLists.txt @@ -66,7 +66,9 @@ make_path(testbinding_include_dirs ${pyside2_BINARY_DIR} make_path(testbinding_typesystem_path ${pyside2_SOURCE_DIR} ${pyside2_BINARY_DIR}) -add_custom_command(OUTPUT ${testbinding_SRC} +add_custom_command( +OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log" +BYPRODUCTS ${testbinding_SRC} COMMAND ${SHIBOKEN_BINARY} ${GENERATOR_EXTRA_FLAGS} ${CMAKE_CURRENT_SOURCE_DIR}/pysidetest_global.h --include-paths=${testbinding_include_dirs} @@ -116,6 +118,7 @@ target_link_libraries(testbinding ${SBK_PYTHON_LIBRARIES}) add_dependencies(testbinding pyside2 QtCore QtGui QtWidgets pysidetest) +create_generator_target(testbinding) PYSIDE_TEST(decoratedslot_test.py) # Will always crash when built against Qt 5.6, no point in running it. diff --git a/sources/shiboken2/generator/generator.cpp b/sources/shiboken2/generator/generator.cpp index 85a8c4769..8b37b44e0 100644 --- a/sources/shiboken2/generator/generator.cpp +++ b/sources/shiboken2/generator/generator.cpp @@ -395,20 +395,7 @@ bool Generator::generateFileForContext(GeneratorContext &context) generateClass(fileOut.stream, context); - FileOut::State state = fileOut.done(); - switch (state) { - case FileOut::Failure: - return false; - case FileOut::Unchanged: - // Even if contents is unchanged, the last file modification time should be updated, - // so that the build system can rely on the fact the generated file is up-to-date. - fileOut.touch(); - break; - case FileOut::Success: - break; - } - - return true; + return fileOut.done() != FileOut::Failure; } QString Generator::getFileNameBaseForSmartPointer(const AbstractMetaType *smartPointerType, diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp index 6d16e1bfb..99947d347 100644 --- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp @@ -3801,7 +3801,7 @@ void CppGenerator::writeClassDefinition(QTextStream &s, if (metaClass->isNamespace() || metaClass->hasPrivateDestructor()) { tp_dealloc = metaClass->hasPrivateDestructor() ? QLatin1String("SbkDeallocWrapperWithPrivateDtor") : - QLatin1String("SbkDummyDealloc /* PYSIDE-595: Prevent replacement of \"0\" with subtype_dealloc. */"); + QLatin1String("object_dealloc /* PYSIDE-832: Prevent replacement of \"0\" with subtype_dealloc. */"); tp_init = QLatin1String("0"); } else { QString deallocClassName; @@ -5732,19 +5732,7 @@ bool CppGenerator::finishGeneration() s << "SBK_MODULE_INIT_FUNCTION_END" << endl; - switch (file.done()) { - case FileOut::Failure: - return false; - case FileOut::Unchanged: - // Even if contents is unchanged, the last file modification time should be updated, - // so that the build system can rely on the fact the generated file is up-to-date. - file.touch(); - break; - case FileOut::Success: - break; - } - - return true; + return file.done() != FileOut::Failure; } static ArgumentOwner getArgumentOwner(const AbstractMetaFunction* func, int argIndex) diff --git a/sources/shiboken2/generator/shiboken2/headergenerator.cpp b/sources/shiboken2/generator/shiboken2/headergenerator.cpp index 9bb5fafde..8881d71f4 100644 --- a/sources/shiboken2/generator/shiboken2/headergenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/headergenerator.cpp @@ -32,6 +32,8 @@ #include <reporthandler.h> #include <fileout.h> +#include <algorithm> + #include <QtCore/QDir> #include <QtCore/QTextStream> #include <QtCore/QVariant> @@ -378,7 +380,12 @@ bool HeaderGenerator::finishGeneration() macrosStream << "// Type indices\nenum : int {\n"; AbstractMetaEnumList globalEnums = this->globalEnums(); - const AbstractMetaClassList &classList = classes(); + AbstractMetaClassList classList = classes(); + + std::sort(classList.begin(), classList.end(), [](AbstractMetaClass *a, AbstractMetaClass* b) { + return a->typeEntry()->sbkIndex() < b->typeEntry()->sbkIndex(); + }); + for (const AbstractMetaClass *metaClass : classList) { writeTypeIndexValueLines(macrosStream, metaClass); lookForEnumsInClassesNotToBeGenerated(globalEnums, metaClass); diff --git a/sources/shiboken2/libshiboken/basewrapper.cpp b/sources/shiboken2/libshiboken/basewrapper.cpp index 2f5f27989..c9e3b9d1b 100644 --- a/sources/shiboken2/libshiboken/basewrapper.cpp +++ b/sources/shiboken2/libshiboken/basewrapper.cpp @@ -447,8 +447,10 @@ PyObject* SbkQAppTpNew(PyTypeObject* subtype, PyObject *, PyObject *) } void -SbkDummyDealloc(PyObject *) -{} +object_dealloc(PyObject *self) +{ + Py_TYPE(self)->tp_free(self); +} PyObject * SbkDummyNew(PyTypeObject *type, PyObject*, PyObject*) diff --git a/sources/shiboken2/libshiboken/basewrapper.h b/sources/shiboken2/libshiboken/basewrapper.h index f8940b842..65849d783 100644 --- a/sources/shiboken2/libshiboken/basewrapper.h +++ b/sources/shiboken2/libshiboken/basewrapper.h @@ -109,17 +109,15 @@ LIBSHIBOKEN_API PyObject* SbkObjectTpNew(PyTypeObject* subtype, PyObject*, PyObj LIBSHIBOKEN_API PyObject* SbkQAppTpNew(PyTypeObject *subtype, PyObject *args, PyObject *kwds); /** - * PYSIDE-595: Use a null deallocator instead of nullptr. + * PYSIDE-832: Use object_dealloc instead of nullptr. * * When moving to heaptypes, we were struck by a special default behavior of * PyType_FromSpecWithBases that inserts subtype_dealloc when tp_dealloc is - * nullptr. To prevent inserting this, we use a null deallocator that is there - * as a placeholder. - * - * The same holds for a null tp_new. We use one that raises the right error. + * nullptr. But the default before conversion to heaptypes was to assign + * object_dealloc. This seems to be a bug in the Limited API. */ -LIBSHIBOKEN_API void SbkDummyDealloc(PyObject*); -LIBSHIBOKEN_API PyObject *SbkDummyNew(PyTypeObject *type, PyObject*, PyObject*); +LIBSHIBOKEN_API void object_dealloc(PyObject *); +LIBSHIBOKEN_API PyObject *SbkDummyNew(PyTypeObject *type, PyObject *, PyObject *); } // extern "C" diff --git a/sources/shiboken2/libshiboken/pep384impl_doc.rst b/sources/shiboken2/libshiboken/pep384impl_doc.rst index 9974f737b..2844249ad 100644 --- a/sources/shiboken2/libshiboken/pep384impl_doc.rst +++ b/sources/shiboken2/libshiboken/pep384impl_doc.rst @@ -426,11 +426,16 @@ many headaches:: type->tp_dealloc = subtype_dealloc; } -So, if you think you have no ``tp_dealloc`` field set, you will unwantedly -get ``subtype_dealloc``, which in the case of PySide always was wrong! +In fact, before the move to the new API, the ``PyType_Ready`` function +filled empty ``tp_dealloc`` fields with ``object_dealloc``. And the code +that has been written with that in mind now becomes pretty wrong if suddenly +``subtype_dealloc`` is used. + +The way out was to explicitly provide an ``object_dealloc`` function. +This would then again impose a problem, because ``object_dealloc`` is not +public. Writing our own version is easy, but it again needs access to +type objects. But fortunately, we have broken this rule, already... -The way out was to use a dummy function that has no effect other than -being something not NULL. * The new types are only partially allocated diff --git a/sources/shiboken2/libshiboken/sbkenum.cpp b/sources/shiboken2/libshiboken/sbkenum.cpp index 4d516f1e8..3c6582adc 100644 --- a/sources/shiboken2/libshiboken/sbkenum.cpp +++ b/sources/shiboken2/libshiboken/sbkenum.cpp @@ -512,7 +512,7 @@ static PyType_Slot SbkNewType_slots[] = { {Py_nb_index, (void *)enum_int}, {Py_tp_richcompare, (void *)enum_richcompare}, {Py_tp_hash, (void *)enum_hash}, - {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {Py_tp_dealloc, (void *)object_dealloc}, {0, 0} }; static PyType_Spec SbkNewType_spec = { diff --git a/sources/shiboken2/libshiboken/voidptr.cpp b/sources/shiboken2/libshiboken/voidptr.cpp index 3a0dbb434..0d7b6b9cd 100644 --- a/sources/shiboken2/libshiboken/voidptr.cpp +++ b/sources/shiboken2/libshiboken/voidptr.cpp @@ -224,7 +224,7 @@ static PyType_Slot SbkVoidPtrType_slots[] = { {Py_tp_richcompare, (void *)SbkVoidPtrObject_richcmp}, {Py_tp_init, (void *)SbkVoidPtrObject_init}, {Py_tp_new, (void *)SbkVoidPtrObject_new}, - {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {Py_tp_dealloc, (void *)object_dealloc}, {0, 0} }; static PyType_Spec SbkVoidPtrType_spec = { diff --git a/sources/shiboken2/shibokenmodule/CMakeLists.txt b/sources/shiboken2/shibokenmodule/CMakeLists.txt index 517aecba8..20baf9f7e 100644 --- a/sources/shiboken2/shibokenmodule/CMakeLists.txt +++ b/sources/shiboken2/shibokenmodule/CMakeLists.txt @@ -12,7 +12,9 @@ set(shibokenmodule_TYPESYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/typesystem_shiboken.xml ) -add_custom_command(OUTPUT ${sample_SRC} +add_custom_command( +OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log" +BYPRODUCTS ${sample_SRC} # Note: shiboken2 is an executable target. By not specifying its explicit # path, CMAKE figures it out, itself! # This fixes an issue with Visual Studio, see https://github.com/PySide/shiboken2/pull/11 @@ -39,6 +41,7 @@ target_link_libraries(shibokenmodule libshiboken) add_dependencies(shibokenmodule shiboken2) +create_generator_target(shibokenmodule) install(TARGETS shibokenmodule DESTINATION ${PYTHON_SITE_PACKAGES}/shiboken2) diff --git a/sources/shiboken2/tests/minimalbinding/CMakeLists.txt b/sources/shiboken2/tests/minimalbinding/CMakeLists.txt index b8b6417d1..ec674b56b 100644 --- a/sources/shiboken2/tests/minimalbinding/CMakeLists.txt +++ b/sources/shiboken2/tests/minimalbinding/CMakeLists.txt @@ -15,7 +15,9 @@ ${CMAKE_CURRENT_BINARY_DIR}/minimal/minbooluser_wrapper.cpp configure_file("${CMAKE_CURRENT_SOURCE_DIR}/minimal-binding.txt.in" "${CMAKE_CURRENT_BINARY_DIR}/minimal-binding.txt" @ONLY) -add_custom_command(OUTPUT ${minimal_SRC} +add_custom_command( +OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log" +BYPRODUCTS ${minimal_SRC} COMMAND shiboken2 --project-file=${CMAKE_CURRENT_BINARY_DIR}/minimal-binding.txt ${GENERATOR_EXTRA_FLAGS} DEPENDS ${minimal_TYPESYSTEM} ${CMAKE_CURRENT_SOURCE_DIR}/global.h shiboken2 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} @@ -38,3 +40,4 @@ target_link_libraries(minimal libminimal ${SBK_PYTHON_LIBRARIES} libshiboken) +create_generator_target(minimal) diff --git a/sources/shiboken2/tests/otherbinding/CMakeLists.txt b/sources/shiboken2/tests/otherbinding/CMakeLists.txt index 186766b41..0be66f797 100644 --- a/sources/shiboken2/tests/otherbinding/CMakeLists.txt +++ b/sources/shiboken2/tests/otherbinding/CMakeLists.txt @@ -17,7 +17,9 @@ ${CMAKE_CURRENT_BINARY_DIR}/other/other_module_wrapper.cpp configure_file("${CMAKE_CURRENT_SOURCE_DIR}/other-binding.txt.in" "${CMAKE_CURRENT_BINARY_DIR}/other-binding.txt" @ONLY) -add_custom_command(OUTPUT ${other_SRC} +add_custom_command( +OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log" +BYPRODUCTS ${other_SRC} COMMAND shiboken2 --project-file=${CMAKE_CURRENT_BINARY_DIR}/other-binding.txt ${GENERATOR_EXTRA_FLAGS} DEPENDS ${other_TYPESYSTEM} ${CMAKE_CURRENT_SOURCE_DIR}/global.h shiboken2 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} @@ -48,4 +50,5 @@ target_link_libraries(other libshiboken) add_dependencies(other sample) +create_generator_target(other) diff --git a/sources/shiboken2/tests/samplebinding/CMakeLists.txt b/sources/shiboken2/tests/samplebinding/CMakeLists.txt index ca737ca08..7f4bec5f4 100644 --- a/sources/shiboken2/tests/samplebinding/CMakeLists.txt +++ b/sources/shiboken2/tests/samplebinding/CMakeLists.txt @@ -128,7 +128,9 @@ ${CMAKE_CURRENT_BINARY_DIR}/sample/union_wrapper.cpp configure_file("${CMAKE_CURRENT_SOURCE_DIR}/sample-binding.txt.in" "${CMAKE_CURRENT_BINARY_DIR}/sample-binding.txt" @ONLY) -add_custom_command(OUTPUT ${sample_SRC} +add_custom_command( +OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log" +BYPRODUCTS ${sample_SRC} COMMAND shiboken2 --project-file=${CMAKE_CURRENT_BINARY_DIR}/sample-binding.txt ${GENERATOR_EXTRA_FLAGS} DEPENDS ${sample_TYPESYSTEM} ${CMAKE_CURRENT_SOURCE_DIR}/global.h shiboken2 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} @@ -152,3 +154,4 @@ target_link_libraries(sample libsample ${SBK_PYTHON_LIBRARIES} libshiboken) +create_generator_target(sample) diff --git a/sources/shiboken2/tests/smartbinding/CMakeLists.txt b/sources/shiboken2/tests/smartbinding/CMakeLists.txt index faaa797b6..43888fae2 100644 --- a/sources/shiboken2/tests/smartbinding/CMakeLists.txt +++ b/sources/shiboken2/tests/smartbinding/CMakeLists.txt @@ -16,7 +16,9 @@ ${CMAKE_CURRENT_BINARY_DIR}/smart/registry_wrapper.cpp configure_file("${CMAKE_CURRENT_SOURCE_DIR}/smart-binding.txt.in" "${CMAKE_CURRENT_BINARY_DIR}/smart-binding.txt" @ONLY) -add_custom_command(OUTPUT ${smart_SRC} +add_custom_command( +OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log" +BYPRODUCTS ${smart_SRC} COMMAND shiboken2 --project-file=${CMAKE_CURRENT_BINARY_DIR}/smart-binding.txt ${GENERATOR_EXTRA_FLAGS} DEPENDS ${smart_TYPESYSTEM} ${CMAKE_CURRENT_SOURCE_DIR}/global.h shiboken2 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} @@ -40,3 +42,4 @@ target_link_libraries(smart libsmart ${SBK_PYTHON_LIBRARIES} libshiboken) +create_generator_target(smart) |