From b840d2a64295b643288f21e46ec9c197245fd89b Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Mon, 5 Jan 2026 17:14:15 -0500 Subject: [PATCH 01/30] Revert part of r91 preventing QFlags from being wrapped By checking if an enum member has already been cached it is not required anymore to skip it if is a QFlags. Additionally, the wrapping of QFlags can now be done by using only Q_FLAGS without having a corresponding Q_ENUMS. Cherry-picked from https://github.com/commontk/PythonQt/commit/86068fdc0534b18e0ff04abb109811eca1be7d52 --- src/PythonQtClassInfo.cpp | 11 +++++----- tests/PythonQtTests.cpp | 46 +++++++++++++++++++++++++++++++++++++++ tests/PythonQtTests.h | 25 +++++++++++++++++++++ 3 files changed, 76 insertions(+), 6 deletions(-) diff --git a/src/PythonQtClassInfo.cpp b/src/PythonQtClassInfo.cpp index 68799e33f..6cd6120c0 100644 --- a/src/PythonQtClassInfo.cpp +++ b/src/PythonQtClassInfo.cpp @@ -289,10 +289,12 @@ bool PythonQtClassInfo::lookForEnumAndCache(const QMetaObject* meta, const char* int enumCount = meta->enumeratorCount(); for (int i = 0; i < enumCount; i++) { QMetaEnum e = meta->enumerator(i); - // we do not want flags, they will cause our values to appear two times - if (e.isFlag()) + if (_cachedMembers.contains(memberName)) { +#ifdef PYTHONQT_DEBUG + std::cout << "cached enum " << memberName << " on " << meta->className() << std::endl; +#endif continue; - + } for (int j = 0; j < e.keyCount(); j++) { if (escapeReservedNames(e.key(j)) == memberName) { PyObject* enumType = findEnumWrapper(e.name()); @@ -558,9 +560,6 @@ QStringList PythonQtClassInfo::memberList() for (int i = 0; i < meta->enumeratorCount(); i++) { QMetaEnum e = meta->enumerator(i); l << e.name(); - // we do not want flags, they will cause our values to appear two times - if (e.isFlag()) - continue; for (int j = 0; j < e.keyCount(); j++) { l << QString(e.key(j)); diff --git a/tests/PythonQtTests.cpp b/tests/PythonQtTests.cpp index b9286e48b..39ed288ee 100644 --- a/tests/PythonQtTests.cpp +++ b/tests/PythonQtTests.cpp @@ -393,6 +393,24 @@ void PythonQtTestSlotCalling::testCppFactory() QVERIFY(_helper->runScript( "obj.testNoArg()\nfrom PythonQt.private import PQCppObject2\na = PQCppObject2()\nif " "a.testEnumFlag3(PQCppObject2.TestEnumValue2)==PQCppObject2.TestEnumValue2: obj.setPassed();\n")); + + PythonQt::self()->registerCPPClass("PQCppObjectQFlagOnly", NULL, NULL, + PythonQtCreateObject); + + // local enum (decorated) + QVERIFY(_helper->runScript( + "obj.testNoArg()\nfrom PythonQt.private import PQCppObjectQFlagOnly\na = PQCppObjectQFlagOnly()\nprint " + "(a.testEnumFlag1)\nif a.testEnumFlag1(PQCppObjectQFlagOnly.TestEnumValue2)==PQCppObjectQFlagOnly.TestEnumValue2: " + "obj.setPassed();\n")); + + // enum with namespace (decorated) + QVERIFY(_helper->runScript( + "obj.testNoArg()\nfrom PythonQt.private import PQCppObjectQFlagOnly\na = PQCppObjectQFlagOnly()\nif " + "a.testEnumFlag2(PQCppObjectQFlagOnly.TestEnumValue2)==PQCppObjectQFlagOnly.TestEnumValue2: obj.setPassed();\n")); + // with int overload to check overloading + QVERIFY(_helper->runScript( + "obj.testNoArg()\nfrom PythonQt.private import PQCppObjectQFlagOnly\na = PQCppObjectQFlagOnly()\nif " + "a.testEnumFlag3(PQCppObjectQFlagOnly.TestEnumValue2)==PQCppObjectQFlagOnly.TestEnumValue2: obj.setPassed();\n")); } PQCppObject2Decorator::TestEnumFlag PQCppObject2Decorator::testEnumFlag1(PQCppObject2* /*obj*/, @@ -417,6 +435,34 @@ PQCppObject2Decorator::TestEnumFlag PQCppObject2Decorator::testEnumFlag3(PQCppOb return flag; } +// PQCppObjectQFlagOnlyDecorator + +PQCppObjectQFlagOnlyDecorator::TestEnumFlag PQCppObjectQFlagOnlyDecorator::testEnumFlag1(PQCppObjectQFlagOnly* obj, + PQCppObjectQFlagOnlyDecorator::TestEnumFlag flag) +{ + return flag; +} + +PQCppObjectQFlagOnly::TestEnumFlag PQCppObjectQFlagOnlyDecorator::testEnumFlag2(PQCppObjectQFlagOnly* obj, + PQCppObjectQFlagOnly::TestEnumFlag flag) +{ + return flag; +} + +// with int overload +PQCppObjectQFlagOnlyDecorator::TestEnumFlag PQCppObjectQFlagOnlyDecorator::testEnumFlag3(PQCppObjectQFlagOnly* obj, + int flag) +{ + return (TestEnumFlag)-1; +} +PQCppObjectQFlagOnlyDecorator::TestEnumFlag PQCppObjectQFlagOnlyDecorator::testEnumFlag3(PQCppObjectQFlagOnly* obj, + PQCppObjectQFlagOnlyDecorator::TestEnumFlag flag) +{ + return flag; +} + +// PythonQtTestSlotCalling + void PythonQtTestSlotCalling::testMultiArgsSlotCall() { QVERIFY(_helper->runScript("if obj.getMultiArgs(12,47.11,'test')==(12,47.11,'test'): obj.setPassed();\n")); diff --git a/tests/PythonQtTests.h b/tests/PythonQtTests.h index 3588107d1..14a4b6b4f 100644 --- a/tests/PythonQtTests.h +++ b/tests/PythonQtTests.h @@ -298,6 +298,31 @@ public Q_SLOTS: TestEnumFlag testEnumFlag3(PQCppObject2* obj, TestEnumFlag flag); }; +typedef PQCppObject2 PQCppObjectQFlagOnly; + +class PQCppObjectQFlagOnlyDecorator : public QObject +{ + Q_OBJECT + +public: + Q_FLAGS(TestEnumFlag) + + enum TestEnumFlag { TestEnumValue1 = 0, TestEnumValue2 = 1 }; + + Q_DECLARE_FLAGS(TestEnum, TestEnumFlag) + +public slots: + PQCppObjectQFlagOnly* new_PQCppObjectQFlagOnly() { return new PQCppObjectQFlagOnly(); } + + TestEnumFlag testEnumFlag1(PQCppObjectQFlagOnly* obj, TestEnumFlag flag); + + PQCppObjectQFlagOnly::TestEnumFlag testEnumFlag2(PQCppObjectQFlagOnly* obj, PQCppObjectQFlagOnly::TestEnumFlag flag); + + // with int overload + TestEnumFlag testEnumFlag3(PQCppObjectQFlagOnly* obj, int flag); + TestEnumFlag testEnumFlag3(PQCppObjectQFlagOnly* obj, TestEnumFlag flag); +}; + class PQUnknownValueObject { public: From 6a0ca0e25f40a4df92eea7f99c8942bee8f622d7 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Wed, 2 Jul 2025 16:36:10 -0400 Subject: [PATCH 02/30] cmake: Re-enable CMake support importing historical improvements from commontk/PythonQt fork MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit partially reverts r431 (which removed unsupported files and added documentation) and consolidates consolidates historical changes developed in the `commontk/PythonQt` fork between 2011 and 2021. Summary: * Qt 5support: * Added initial and ongoing support for Qt5, including modules like `PrintSupport`, `QuickWidgets`, `Multimedia`, and `OpenGL`. * Removed Qt4 support; fixed CMake logic for building across Qt 5.3–5.9. * Introduced `pythonqt_wrap_cpp` macro and cleaned up legacy Qt macros. * Build system enhancements: * Re-enabled and expanded CMake support with configurable install paths and testing. * Removed use of `INSTALL_NAME_DIR` to support relocatable installs. * Addressed build issues across toolchains (e.g., MSVC `/bigobj` workaround, debug mode fixes). * Added missing source files and build flags. * Code quality and compatibility: * Replaced deprecated/legacy constructs (e.g., use of `nullptr`, fixed property aliasing with `name` → `objectName`). * Added support for 511 wrappers. * Resolved warnings and linkage issues with optional build flags (e.g., `PythonQt_Wrap_Qtcore`). * Testing and cleanup: * Added cleanup/finalization unit tests. * Ensured test code compiles cleanly when wrapping is partially disabled. (cherry picked from commit MeVisLab/pythonqt@93c546e281585dfd137b35bf43261ded4620ac30) Co-authored-by: Florian Link <5535644+florianlink@users.noreply.github.com> Co-authored-by: Matthew Woehlke Co-authored-by: Max Smolens Co-authored-by: Pat Marion Co-authored-by: Francois Budin Co-authored-by: Christoph Willing Co-authored-by: Stefan Dinkelacker Co-authored-by: Sylvain Bernhardt --- CMakeLists.txt | 380 +++++++++++++++++++++++++++++++++++++ tests/PythonQtTestMain.cpp | 1 - 2 files changed, 380 insertions(+), 1 deletion(-) create mode 100644 CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..05cc51ff4 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,380 @@ +#----------------------------------------------------------------------------- +# NOTE: The CMake files have been contributed to PythonQt and have not been tested with the current +# PythonQt version. They have not yet been updated to support Qt 5 and/or Python 3. +# +# If you are not a CMake expert, you should better use the provided qmake profiles. +#----------------------------------------------------------------------------- + +cmake_minimum_required(VERSION 3.5) + +project(PythonQt) + +#---------------------------------------------------------------------------- +# Qt version + +# Set PythonQt_QT_VERSION +set(PythonQt_QT_VERSION 5) + +# Requirements +set(minimum_required_qt5_version "5.3.0") +set(minimum_required_qt_version ${minimum_required_qt${PythonQt_QT_VERSION}_version}) + +find_package(Qt5 ${minimum_required_qt_version} QUIET) +set(QT_VERSION_MAJOR ${Qt5_VERSION_MAJOR}) +set(QT_VERSION_MINOR ${Qt5_VERSION_MINOR}) + +#---------------------------------------------------------------------------- +# Qt components +set(qtlibs + Core + Widgets + Network + OpenGL + Sql + Svg + Multimedia + UiTools + Xml + XmlPatterns + ) +# Webkit has been removed in Qt >= 5.6 +if("${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}" VERSION_LESS "5.7") + list(APPEND qtlibs + WebKitWidgets + ) +endif() +if("${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}" VERSION_GREATER "5.5") + list(APPEND qtlibs + Qml + Quick + ) +endif() + +#----------------------------------------------------------------------------- +# Python libraries + +find_package(PythonLibs REQUIRED) +include_directories("${PYTHON_INCLUDE_DIR}") +add_definitions( + -DPYTHONQT_USE_RELEASE_PYTHON_FALLBACK + -DPYTHONQT_SUPPORT_NAME_PROPERTY + ) + +#----------------------------------------------------------------------------- +# Build options + +if(NOT DEFINED PythonQt_INSTALL_RUNTIME_DIR) + set(PythonQt_INSTALL_RUNTIME_DIR bin) +endif() + +if(NOT DEFINED PythonQt_INSTALL_LIBRARY_DIR) + set(PythonQt_INSTALL_LIBRARY_DIR lib${LIB_SUFFIX}) +endif() + +if(NOT DEFINED PythonQt_INSTALL_ARCHIVE_DIR) + set(PythonQt_INSTALL_ARCHIVE_DIR lib${LIB_SUFFIX}) +endif() + +if(NOT DEFINED PythonQt_INSTALL_INCLUDE_DIR) + set(PythonQt_INSTALL_INCLUDE_DIR include/PythonQt) +endif() + +#----------------------------------------------------------------------------- +# Set qtlib_to_wraplib_* variables + +set(qtlib_to_wraplib_Widgets gui) +set(qtlib_to_wraplib_WebKitWidgets webkit) + +set(qt5_wrapped_lib_depends_gui Multimedia PrintSupport) +set(qt5_wrapped_lib_depends_multimedia MultimediaWidgets) +set(qt5_wrapped_lib_depends_quick QuickWidgets) + +foreach(qtlib ${qtlibs}) + string(TOLOWER ${qtlib} qtlib_lowercase) + if(DEFINED qtlib_to_wraplib_${qtlib}) + set(qtlib_lowercase ${qtlib_to_wraplib_${qtlib}}) + endif() + set(qtlib_to_wraplib_${qtlib} ${qtlib_lowercase}) +endforeach() + +#----------------------------------------------------------------------------- +# Define PythonQt_Wrap_Qt* options +option(PythonQt_Wrap_QtAll "Make all Qt components available in python" OFF) +foreach(qtlib ${qtlibs}) + OPTION(PythonQt_Wrap_Qt${qtlib_to_wraplib_${qtlib}} "Make all of Qt${qtlib} available in python" OFF) +endforeach() + +#----------------------------------------------------------------------------- +# Force option if it applies +if(PythonQt_Wrap_QtAll) + foreach(qtlib ${qtlibs}) + # XXX xmlpatterns wrapper does *NOT* build at all :( + if(${qtlib} STREQUAL "XmlPatterns") + continue() + endif() + set(qt_wrapped_lib ${qtlib_to_wraplib_${qtlib}}) + if(NOT ${PythonQt_Wrap_Qt${qt_wrapped_lib}}) + set(PythonQt_Wrap_Qt${qt_wrapped_lib} ON CACHE BOOL "Make all of Qt${qt_wrapped_lib} available in python" FORCE) + message(STATUS "Enabling [PythonQt_Wrap_Qt${qt_wrapped_lib}] because of [PythonQt_Wrap_QtAll] evaluates to True") + endif() + endforeach() +endif() + +option(PythonQt_DEBUG "Enable/Disable PythonQt debug output" OFF) +if(PythonQt_DEBUG) + add_definitions(-DPYTHONQT_DEBUG) +else() + remove_definitions(-DPYTHONQT_DEBUG) +endif() + +#----------------------------------------------------------------------------- +# Setup Qt + +# Required components +set(qt_required_components Core Widgets) +foreach(qtlib ${qtlibs}) + set(qt_wrapped_lib ${qtlib_to_wraplib_${qtlib}}) + if(${PythonQt_Wrap_Qt${qt_wrapped_lib}}) + list(APPEND qt_required_components ${qtlib} ${qt${PythonQt_QT_VERSION}_wrapped_lib_depends_${qt_wrapped_lib}}) + endif() +endforeach() +if(BUILD_TESTING) + list(APPEND qt_required_components Test) +endif() +list(REMOVE_DUPLICATES qt_required_components) + +message(STATUS "${PROJECT_NAME}: Required Qt components [${qt_required_components}]") +find_package(Qt5 ${minimum_required_qt_version} COMPONENTS ${qt_required_components} REQUIRED) + +set(QT_LIBRARIES ) +foreach(qtlib ${qt_required_components}) + include_directories(${Qt5${qtlib}_INCLUDE_DIRS}) + add_definitions(${Qt5${qtlib}_DEFINITIONS}) + list(APPEND QT_LIBRARIES ${Qt5${qtlib}_LIBRARIES}) +endforeach() + +# Required for use of "QtCore/private/qmetaobjectbuilder_p.h" in "PythonQt.cpp" +include_directories(${Qt5Core_PRIVATE_INCLUDE_DIRS}) + +macro(pythonqt_wrap_cpp) + qt5_wrap_cpp(${ARGV}) +endmacro() + +if(UNIX) + find_package(OpenGL) + if(OPENGL_FOUND) + list(APPEND QT_LIBRARIES ${OPENGL_LIBRARIES}) + endif() +endif() + +#----------------------------------------------------------------------------- +# The variable "generated_cpp_suffix" allows to conditionnally compile the generated wrappers +# associated with the Qt version being used. + +set(generated_cpp_suffix_52 _50) +set(generated_cpp_suffix_51 _50) + +set(generated_cpp_suffix "_${QT_VERSION_MAJOR}${QT_VERSION_MINOR}") +if(DEFINED generated_cpp_suffix_${QT_VERSION_MAJOR}${QT_VERSION_MINOR}) + set(generated_cpp_suffix "${generated_cpp_suffix_${QT_VERSION_MAJOR}${QT_VERSION_MINOR}}") +elseif("${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}" VERSION_GREATER "5.10") + set(generated_cpp_suffix "_511") +elseif("${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}" VERSION_GREATER "5.5") + set(generated_cpp_suffix "_56") +elseif("${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}" VERSION_GREATER "5.3") + set(generated_cpp_suffix "_54") +endif() + +#----------------------------------------------------------------------------- +# Sources + +set(sources + src/PythonQtBoolResult.cpp + src/PythonQtClassInfo.cpp + src/PythonQtClassWrapper.cpp + src/PythonQtConversion.cpp + src/PythonQt.cpp + src/PythonQtImporter.cpp + src/PythonQtInstanceWrapper.cpp + src/PythonQtMethodInfo.cpp + src/PythonQtMisc.cpp + src/PythonQtObjectPtr.cpp + src/PythonQtProperty.cpp + src/PythonQtQFileImporter.cpp + src/PythonQtSignalReceiver.cpp + src/PythonQtSlot.cpp + src/PythonQtSlotDecorator.cpp + src/PythonQtSignal.cpp + src/PythonQtStdDecorators.cpp + src/PythonQtStdIn.cpp + src/PythonQtStdOut.cpp + src/PythonQtThreadSupport.cpp + src/gui/PythonQtScriptingConsole.cpp + + generated_cpp${generated_cpp_suffix}/PythonQt_QtBindings.cpp + + generated_cpp${generated_cpp_suffix}/com_trolltech_qt_core_builtin/com_trolltech_qt_core_builtin0.cpp + generated_cpp${generated_cpp_suffix}/com_trolltech_qt_core_builtin/com_trolltech_qt_core_builtin_init.cpp + generated_cpp${generated_cpp_suffix}/com_trolltech_qt_gui_builtin/com_trolltech_qt_gui_builtin0.cpp + generated_cpp${generated_cpp_suffix}/com_trolltech_qt_gui_builtin/com_trolltech_qt_gui_builtin_init.cpp +) + +#----------------------------------------------------------------------------- +# List headers. This is list is used for the install command. + +set(headers + src/PythonQtBoolResult.h + src/PythonQtClassInfo.h + src/PythonQtClassWrapper.h + src/PythonQtConversion.h + src/PythonQtCppWrapperFactory.h + src/PythonQtDoc.h + src/PythonQt.h + src/PythonQtImporter.h + src/PythonQtImportFileInterface.h + src/PythonQtInstanceWrapper.h + src/PythonQtMethodInfo.h + src/PythonQtMisc.h + src/PythonQtObjectPtr.h + src/PythonQtProperty.h + src/PythonQtQFileImporter.h + src/PythonQtSignalReceiver.h + src/PythonQtSlot.h + src/PythonQtSlotDecorator.h + src/PythonQtSignal.h + src/PythonQtStdDecorators.h + src/PythonQtStdIn.h + src/PythonQtStdOut.h + src/PythonQtSystem.h + src/PythonQtThreadSupport.h + src/PythonQtUtils.h + src/PythonQtVariants.h + src/PythonQtPythonInclude.h + generated_cpp${generated_cpp_suffix}/PythonQt_QtBindings.h +) + +#----------------------------------------------------------------------------- +# Headers that should run through moc + +set(moc_sources + src/PythonQt.h + src/PythonQtSignalReceiver.h + src/PythonQtStdDecorators.h + src/gui/PythonQtScriptingConsole.h + + generated_cpp${generated_cpp_suffix}/com_trolltech_qt_core_builtin/com_trolltech_qt_core_builtin0.h + generated_cpp${generated_cpp_suffix}/com_trolltech_qt_gui_builtin/com_trolltech_qt_gui_builtin0.h +) + +#----------------------------------------------------------------------------- +# Add extra sources + +foreach(qtlib ${qtlibs}) + + set(qt_wrapped_lib ${qtlib_to_wraplib_${qtlib}}) + + if (${PythonQt_Wrap_Qt${qt_wrapped_lib}}) + + ADD_DEFINITIONS(-DPYTHONQT_WRAP_Qt${qt_wrapped_lib}) + + set(file_prefix generated_cpp${generated_cpp_suffix}/com_trolltech_qt_${qt_wrapped_lib}/com_trolltech_qt_${qt_wrapped_lib}) + + foreach(index RANGE 0 12) + + # Source files + if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${file_prefix}${index}.cpp) + list(APPEND sources ${file_prefix}${index}.cpp) + endif() + + # Headers that should run through moc + if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${file_prefix}${index}.h) + list(APPEND moc_sources ${file_prefix}${index}.h) + endif() + + endforeach() + + list(APPEND sources ${file_prefix}_init.cpp) + + endif() +endforeach() + +#----------------------------------------------------------------------------- +# Do wrapping +pythonqt_wrap_cpp(gen_moc_sources ${moc_sources}) + +#----------------------------------------------------------------------------- +# Build the library + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/src + ) + +add_library(PythonQt SHARED + ${sources} + ${gen_moc_sources} + ) +set_target_properties(PythonQt PROPERTIES DEFINE_SYMBOL PYTHONQT_EXPORTS) + +target_compile_options(PythonQt PRIVATE + $<$:/bigobj> + ) + +target_link_libraries(PythonQt + ${PYTHON_LIBRARY} + ${QT_LIBRARIES} + ) + +#----------------------------------------------------------------------------- +# Install library (on windows, put the dll in 'bin' and the archive in 'lib') + +install(TARGETS PythonQt + RUNTIME DESTINATION ${PythonQt_INSTALL_RUNTIME_DIR} + LIBRARY DESTINATION ${PythonQt_INSTALL_LIBRARY_DIR} + ARCHIVE DESTINATION ${PythonQt_INSTALL_ARCHIVE_DIR}) +install(FILES ${headers} DESTINATION ${PythonQt_INSTALL_INCLUDE_DIR}) + +#----------------------------------------------------------------------------- +# Testing + +option(BUILD_TESTING "Build the testing tree." OFF) +include(CTest) + +if(BUILD_TESTING) + create_test_sourcelist(test_sources PythonQtCppTests.cpp + tests/PythonQtTestMain.cpp + ) + + set_property(SOURCE tests/PythonQtTestMain.cpp PROPERTY COMPILE_DEFINITIONS "main=tests_PythonQtTestMain") + + list(APPEND test_sources + tests/PythonQtTests.cpp + tests/PythonQtTests.h + ) + + pythonqt_wrap_cpp(test_sources + tests/PythonQtTests.h + ) + + if(PythonQt_Wrap_QtCore) + include_directories(generated_cpp${generated_cpp_suffix}) + + list(APPEND test_sources + tests/PythonQtTestCleanup.cpp + tests/PythonQtTestCleanup.h + ) + pythonqt_wrap_cpp(test_sources + tests/PythonQtTestCleanup.h + ) + + set_property(SOURCE tests/PythonQtTestMain.cpp APPEND PROPERTY COMPILE_DEFINITIONS "PythonQt_Wrap_Qtcore") + endif() + + add_executable(PythonQtCppTests ${test_sources}) + target_link_libraries(PythonQtCppTests PythonQt) + + add_test( + NAME tests_PythonQtTestMain + COMMAND ${Slicer_LAUNCH_COMMAND} $ tests/PythonQtTestMain + ) +endif() + diff --git a/tests/PythonQtTestMain.cpp b/tests/PythonQtTestMain.cpp index 1ae76e2a6..09fe6747f 100644 --- a/tests/PythonQtTestMain.cpp +++ b/tests/PythonQtTestMain.cpp @@ -54,7 +54,6 @@ int main(int argc, char* argv[]) QTest::qExec(&test, argc, argv); return 0; } - if (QProcessEnvironment::systemEnvironment().contains("PYTHONQT_RUN_ONLY_CLEANUP_TESTS")) { PythonQtTestCleanup cleanup; QTest::qExec(&cleanup, argc, argv); From 325f05e7dddd93249ee480aece362f6c9223c3b2 Mon Sep 17 00:00:00 2001 From: James Butler Date: Mon, 7 Jul 2025 03:53:06 -0400 Subject: [PATCH 03/30] Fix Qt 5.15 failing to use 5.15 wrappers PythonQt_QtBindings.cpp and PythonQt_QtBindings.h were copied over from the generated_cpp_511 directory. --- CMakeLists.txt | 2 + generated_cpp_515/PythonQt_QtBindings.cpp | 73 +++++++++++++++++++++++ generated_cpp_515/PythonQt_QtBindings.h | 10 ++++ 3 files changed, 85 insertions(+) create mode 100644 generated_cpp_515/PythonQt_QtBindings.cpp create mode 100644 generated_cpp_515/PythonQt_QtBindings.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 05cc51ff4..77dacd42b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -177,6 +177,8 @@ set(generated_cpp_suffix_51 _50) set(generated_cpp_suffix "_${QT_VERSION_MAJOR}${QT_VERSION_MINOR}") if(DEFINED generated_cpp_suffix_${QT_VERSION_MAJOR}${QT_VERSION_MINOR}) set(generated_cpp_suffix "${generated_cpp_suffix_${QT_VERSION_MAJOR}${QT_VERSION_MINOR}}") +elseif("${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}" VERSION_GREATER "5.14") + set(generated_cpp_suffix "_515") elseif("${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}" VERSION_GREATER "5.10") set(generated_cpp_suffix "_511") elseif("${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}" VERSION_GREATER "5.5") diff --git a/generated_cpp_515/PythonQt_QtBindings.cpp b/generated_cpp_515/PythonQt_QtBindings.cpp new file mode 100644 index 000000000..c6f8d4b09 --- /dev/null +++ b/generated_cpp_515/PythonQt_QtBindings.cpp @@ -0,0 +1,73 @@ + +#include "PythonQt_QtBindings.h" + +#include "PythonQt.h" + +void PythonQt_init_QtGui(PyObject*); +void PythonQt_init_QtSvg(PyObject*); +void PythonQt_init_QtSql(PyObject*); +void PythonQt_init_QtNetwork(PyObject*); +void PythonQt_init_QtCore(PyObject*); +void PythonQt_init_QtWebKit(PyObject*); +void PythonQt_init_QtOpenGL(PyObject*); +void PythonQt_init_QtQml(PyObject*); +void PythonQt_init_QtQuick(PyObject*); +void PythonQt_init_QtXml(PyObject*); +void PythonQt_init_QtXmlPatterns(PyObject*); +void PythonQt_init_QtUiTools(PyObject*); +void PythonQt_init_QtMultimedia(PyObject*); + +PYTHONQT_EXPORT void PythonQt_init_QtBindings() + { + #ifdef PYTHONQT_WRAP_Qtcore + PythonQt_init_QtCore(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtgui + PythonQt_init_QtGui(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtnetwork + PythonQt_init_QtNetwork(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtopengl + PythonQt_init_QtOpenGL(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtqml + PythonQt_init_QtQml(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtquick + PythonQt_init_QtQuick(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtsql + PythonQt_init_QtSql(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtsvg + PythonQt_init_QtSvg(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtuitools + PythonQt_init_QtUiTools(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtmultimedia + PythonQt_init_QtMultimedia(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtwebkit + PythonQt_init_QtWebKit(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtxml + PythonQt_init_QtXml(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtxmlpatterns + PythonQt_init_QtXmlPatterns(0); + #endif + }; diff --git a/generated_cpp_515/PythonQt_QtBindings.h b/generated_cpp_515/PythonQt_QtBindings.h new file mode 100644 index 000000000..03e96aed8 --- /dev/null +++ b/generated_cpp_515/PythonQt_QtBindings.h @@ -0,0 +1,10 @@ +#ifndef _PYTHONQT_QTBINDINGS_H +#define _PYTHONQT_QTBINDINGS_H + +#include "PythonQtSystem.h" + +/// Initialize Qt bindings enabled at configuration time +PYTHONQT_EXPORT void PythonQt_init_QtBindings(); + +#endif + From 2fb62724d7959c740f0f244af280e83b34efa2de Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Mon, 1 Sep 2025 02:56:46 -0400 Subject: [PATCH 04/30] Update PythonQtTestCleanup to adapt to this fork layout --- tests/PythonQtTestCleanup.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/PythonQtTestCleanup.cpp b/tests/PythonQtTestCleanup.cpp index 862931215..2459cf6a3 100644 --- a/tests/PythonQtTestCleanup.cpp +++ b/tests/PythonQtTestCleanup.cpp @@ -1,6 +1,6 @@ #include "PythonQtTestCleanup.h" #include "PythonQt.h" -#include "PythonQt_QtAll.h" +#include "PythonQt_QtBindings.h" void PythonQtTestCleanup::initTestCase() {} @@ -11,7 +11,7 @@ void PythonQtTestCleanup::init() // Initialize before each test PythonQt::init(PythonQt::IgnoreSiteModule); - PythonQt_QtAll::init(); + PythonQt_init_QtBindings(); _helper = new PythonQtTestCleanupHelper(); PythonQtObjectPtr main = PythonQt::self()->getMainModule(); From a6e735b95b5015e20bddcaec2108dd85469685be Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Thu, 23 Oct 2025 04:34:34 -0400 Subject: [PATCH 05/30] cmake: Set PYTHONQT_SUPPORT_NAME_PROPERTY as target compile property This changes the `PYTHONQT_SUPPORT_NAME_PROPERTY` definition from a global `add_definition` to a target-specific compile definition and adds the CMake option `PythonQt_SUPPORT_NAME_PROPERTY` set to ON by default. --- CMakeLists.txt | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 77dacd42b..51a8da285 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,12 +57,13 @@ find_package(PythonLibs REQUIRED) include_directories("${PYTHON_INCLUDE_DIR}") add_definitions( -DPYTHONQT_USE_RELEASE_PYTHON_FALLBACK - -DPYTHONQT_SUPPORT_NAME_PROPERTY ) #----------------------------------------------------------------------------- # Build options +option(PythonQt_SUPPORT_NAME_PROPERTY "Enable PythonQt name-property support" ON) + if(NOT DEFINED PythonQt_INSTALL_RUNTIME_DIR) set(PythonQt_INSTALL_RUNTIME_DIR bin) endif() @@ -317,6 +318,11 @@ add_library(PythonQt SHARED ) set_target_properties(PythonQt PROPERTIES DEFINE_SYMBOL PYTHONQT_EXPORTS) +target_compile_definitions(PythonQt + PRIVATE + $<$:PYTHONQT_SUPPORT_NAME_PROPERTY> + ) + target_compile_options(PythonQt PRIVATE $<$:/bigobj> ) @@ -374,6 +380,11 @@ if(BUILD_TESTING) add_executable(PythonQtCppTests ${test_sources}) target_link_libraries(PythonQtCppTests PythonQt) + target_compile_definitions(PythonQtCppTests + PRIVATE + $<$:PYTHONQT_SUPPORT_NAME_PROPERTY> + ) + add_test( NAME tests_PythonQtTestMain COMMAND ${Slicer_LAUNCH_COMMAND} $ tests/PythonQtTestMain From 726cbfcd231623c430a0c001bd6a21183516905a Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Thu, 23 Oct 2025 09:35:31 -0400 Subject: [PATCH 06/30] cmake: Set PYTHONQT_USE_RELEASE_PYTHON_FALLBACK as target compile property This converts the `PYTHONQT_USE_RELEASE_PYTHON_FALLBACK` definition from a global add_definition to a target-specific compile definition and adds the CMake option `PythonQt_USE_RELEASE_PYTHON_FALLBACK` set to ON by default. --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 51a8da285..2be77aa56 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,14 +55,12 @@ endif() find_package(PythonLibs REQUIRED) include_directories("${PYTHON_INCLUDE_DIR}") -add_definitions( - -DPYTHONQT_USE_RELEASE_PYTHON_FALLBACK - ) #----------------------------------------------------------------------------- # Build options option(PythonQt_SUPPORT_NAME_PROPERTY "Enable PythonQt name-property support" ON) +option(PythonQt_USE_RELEASE_PYTHON_FALLBACK "Fallback to Release python when Debug missing" ON) if(NOT DEFINED PythonQt_INSTALL_RUNTIME_DIR) set(PythonQt_INSTALL_RUNTIME_DIR bin) @@ -321,6 +319,8 @@ set_target_properties(PythonQt PROPERTIES DEFINE_SYMBOL PYTHONQT_EXPORTS) target_compile_definitions(PythonQt PRIVATE $<$:PYTHONQT_SUPPORT_NAME_PROPERTY> + PUBLIC + $<$:PYTHONQT_USE_RELEASE_PYTHON_FALLBACK> ) target_compile_options(PythonQt PRIVATE From cc6e3ca4202a2f08d0df413e2bc497c33575d3fd Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Thu, 23 Oct 2025 05:34:06 -0400 Subject: [PATCH 07/30] cmake: Set include directories as target compile property This changes the include directories from global include_directories to target-specific target_include_directories. This improves the encapsulation and modularity of the build. --- CMakeLists.txt | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2be77aa56..f888deda9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -152,9 +152,6 @@ foreach(qtlib ${qt_required_components}) list(APPEND QT_LIBRARIES ${Qt5${qtlib}_LIBRARIES}) endforeach() -# Required for use of "QtCore/private/qmetaobjectbuilder_p.h" in "PythonQt.cpp" -include_directories(${Qt5Core_PRIVATE_INCLUDE_DIRS}) - macro(pythonqt_wrap_cpp) qt5_wrap_cpp(${ARGV}) endmacro() @@ -306,10 +303,6 @@ pythonqt_wrap_cpp(gen_moc_sources ${moc_sources}) #----------------------------------------------------------------------------- # Build the library -include_directories( - ${CMAKE_CURRENT_SOURCE_DIR}/src - ) - add_library(PythonQt SHARED ${sources} ${gen_moc_sources} @@ -327,6 +320,15 @@ target_compile_options(PythonQt PRIVATE $<$:/bigobj> ) +target_include_directories(PythonQt + PUBLIC + $ + $ + PRIVATE + # Required for use of "QtCore/private/qmetaobjectbuilder_p.h" in "PythonQt.cpp" + ${Qt5Core_PRIVATE_INCLUDE_DIRS} + ) + target_link_libraries(PythonQt ${PYTHON_LIBRARY} ${QT_LIBRARIES} @@ -364,8 +366,6 @@ if(BUILD_TESTING) ) if(PythonQt_Wrap_QtCore) - include_directories(generated_cpp${generated_cpp_suffix}) - list(APPEND test_sources tests/PythonQtTestCleanup.cpp tests/PythonQtTestCleanup.h @@ -374,10 +374,16 @@ if(BUILD_TESTING) tests/PythonQtTestCleanup.h ) - set_property(SOURCE tests/PythonQtTestMain.cpp APPEND PROPERTY COMPILE_DEFINITIONS "PythonQt_Wrap_Qtcore") + set_property(SOURCE tests/PythonQtTestMain.cpp APPEND PROPERTY COMPILE_DEFINITIONS "PythonQt_Wrap_QtCore") endif() add_executable(PythonQtCppTests ${test_sources}) + + target_include_directories(PythonQtCppTests + PRIVATE + $<$:${CMAKE_CURRENT_SOURCE_DIR}/generated_cpp${generated_cpp_suffix}> + ) + target_link_libraries(PythonQtCppTests PythonQt) target_compile_definitions(PythonQtCppTests From 0a528251fd75b24d915eb1ec2c9eda0753bfa486 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Thu, 23 Oct 2025 05:38:31 -0400 Subject: [PATCH 08/30] cmake: Set PYTHONQT_DEBUG as target compile property This changes the PYTHONQT_DEBUG definition from a global add_definition to a target-specific compile definition. --- CMakeLists.txt | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f888deda9..e1ebb0627 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,6 +61,7 @@ include_directories("${PYTHON_INCLUDE_DIR}") option(PythonQt_SUPPORT_NAME_PROPERTY "Enable PythonQt name-property support" ON) option(PythonQt_USE_RELEASE_PYTHON_FALLBACK "Fallback to Release python when Debug missing" ON) +option(PythonQt_DEBUG "Enable PythonQt debug output" OFF) if(NOT DEFINED PythonQt_INSTALL_RUNTIME_DIR) set(PythonQt_INSTALL_RUNTIME_DIR bin) @@ -119,13 +120,6 @@ if(PythonQt_Wrap_QtAll) endforeach() endif() -option(PythonQt_DEBUG "Enable/Disable PythonQt debug output" OFF) -if(PythonQt_DEBUG) - add_definitions(-DPYTHONQT_DEBUG) -else() - remove_definitions(-DPYTHONQT_DEBUG) -endif() - #----------------------------------------------------------------------------- # Setup Qt @@ -311,6 +305,7 @@ set_target_properties(PythonQt PROPERTIES DEFINE_SYMBOL PYTHONQT_EXPORTS) target_compile_definitions(PythonQt PRIVATE + $<$:PYTHONQT_DEBUG> $<$:PYTHONQT_SUPPORT_NAME_PROPERTY> PUBLIC $<$:PYTHONQT_USE_RELEASE_PYTHON_FALLBACK> From 19f3c5edc2284f3e6aaee808f11af428094d0ffa Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Thu, 23 Oct 2025 05:55:25 -0400 Subject: [PATCH 09/30] cmake: Simplify Qt5 integration leveraging Qt5 imported targets This simplifies Qt5 integration by using Qt5 imported targets instead of manually including directories and definitions. --- CMakeLists.txt | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e1ebb0627..b84ac9d61 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -140,10 +140,8 @@ message(STATUS "${PROJECT_NAME}: Required Qt components [${qt_required_component find_package(Qt5 ${minimum_required_qt_version} COMPONENTS ${qt_required_components} REQUIRED) set(QT_LIBRARIES ) -foreach(qtlib ${qt_required_components}) - include_directories(${Qt5${qtlib}_INCLUDE_DIRS}) - add_definitions(${Qt5${qtlib}_DEFINITIONS}) - list(APPEND QT_LIBRARIES ${Qt5${qtlib}_LIBRARIES}) +foreach(qt_component ${qt_required_components}) + list(APPEND QT_LIBRARIES Qt5::${qt_component}) endforeach() macro(pythonqt_wrap_cpp) @@ -325,8 +323,9 @@ target_include_directories(PythonQt ) target_link_libraries(PythonQt - ${PYTHON_LIBRARY} - ${QT_LIBRARIES} + PUBLIC + ${PYTHON_LIBRARY} + ${QT_LIBRARIES} ) #----------------------------------------------------------------------------- From dec399cf3c783dd1e4f68221f82781bc43572d21 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Thu, 23 Oct 2025 07:02:13 -0400 Subject: [PATCH 10/30] cmake: Remove obsolete support for generated_cpp different from generated_cpp_5.15 This removes obsolete support for generated_cpp configurations other than 5.15. --- CMakeLists.txt | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b84ac9d61..213e09d30 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -159,20 +159,10 @@ endif() # The variable "generated_cpp_suffix" allows to conditionnally compile the generated wrappers # associated with the Qt version being used. -set(generated_cpp_suffix_52 _50) -set(generated_cpp_suffix_51 _50) - -set(generated_cpp_suffix "_${QT_VERSION_MAJOR}${QT_VERSION_MINOR}") -if(DEFINED generated_cpp_suffix_${QT_VERSION_MAJOR}${QT_VERSION_MINOR}) - set(generated_cpp_suffix "${generated_cpp_suffix_${QT_VERSION_MAJOR}${QT_VERSION_MINOR}}") -elseif("${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}" VERSION_GREATER "5.14") +if("${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}" VERSION_GREATER_EQUAL "5.15") set(generated_cpp_suffix "_515") -elseif("${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}" VERSION_GREATER "5.10") - set(generated_cpp_suffix "_511") -elseif("${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}" VERSION_GREATER "5.5") - set(generated_cpp_suffix "_56") -elseif("${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}" VERSION_GREATER "5.3") - set(generated_cpp_suffix "_54") +else() + message(FATAL_ERROR "Generated wrappers only available for Qt >= 5.15 (found ${QT_VERSION}).") endif() #----------------------------------------------------------------------------- From 6724d4c36d6019ff6d6fa3e700c52350e3427de1 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Thu, 23 Oct 2025 07:56:32 -0400 Subject: [PATCH 11/30] cmake: Remove support for building against Qt < 5.15 --- CMakeLists.txt | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 213e09d30..20a23b982 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ project(PythonQt) set(PythonQt_QT_VERSION 5) # Requirements -set(minimum_required_qt5_version "5.3.0") +set(minimum_required_qt5_version "5.15.0") set(minimum_required_qt_version ${minimum_required_qt${PythonQt_QT_VERSION}_version}) find_package(Qt5 ${minimum_required_qt_version} QUIET) @@ -30,6 +30,8 @@ set(qtlibs Widgets Network OpenGL + Qml + Quick Sql Svg Multimedia @@ -37,18 +39,6 @@ set(qtlibs Xml XmlPatterns ) -# Webkit has been removed in Qt >= 5.6 -if("${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}" VERSION_LESS "5.7") - list(APPEND qtlibs - WebKitWidgets - ) -endif() -if("${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}" VERSION_GREATER "5.5") - list(APPEND qtlibs - Qml - Quick - ) -endif() #----------------------------------------------------------------------------- # Python libraries From 1db81c503bddbf1546da973ebeba66cb2664528d Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Thu, 23 Oct 2025 08:18:05 -0400 Subject: [PATCH 12/30] cmake: Update minimum required CMake version from 3.5 to 3.20.6 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 20a23b982..40689d063 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ # If you are not a CMake expert, you should better use the provided qmake profiles. #----------------------------------------------------------------------------- -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.20.6) project(PythonQt) From 4a9d122849a103449dd5099300fbab5fd54d5621 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Thu, 23 Oct 2025 08:23:50 -0400 Subject: [PATCH 13/30] cmake: Switch to using FindPython3 CMake module The FindPythonLib CMake module is deprecated since CMake 3.12 and starting with CMake 3.27 the module is not provided unless CMP0148 is set to OLD. To integrate PythonQt in other project, the CMake variables `Python3_LIBRARY` and `Python3_INCLUDE_DIR` may be set instead of `PYTHON_LIBRARY`, `PYTHON_INCLUDE_DIR` and `PYTHON_INCLUDE_DIR2`. Options `Python3_ROOT_DIR`, `Python3_LIBRARY_DEBUG` and `Python3_LIBRARY_RELEASE` may also be set. Co-authored-by: Hans Johnson --- CMakeLists.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 40689d063..9f129bcf6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,8 +43,7 @@ set(qtlibs #----------------------------------------------------------------------------- # Python libraries -find_package(PythonLibs REQUIRED) -include_directories("${PYTHON_INCLUDE_DIR}") +find_package(Python3 COMPONENTS Development REQUIRED) #----------------------------------------------------------------------------- # Build options @@ -304,7 +303,7 @@ target_include_directories(PythonQt target_link_libraries(PythonQt PUBLIC - ${PYTHON_LIBRARY} + Python3::Python ${QT_LIBRARIES} ) From 83a47abd5a5b845974ee00841e2654576fdfcc93 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Thu, 23 Oct 2025 10:34:35 -0400 Subject: [PATCH 14/30] cmake: Add `PythonQtConfigure.h` to map CMake option to public macro Introduce `PythonQtConfigure.h` to derive `PYTHONQT_USE_RELEASE_PYTHON_FALLBACK` from the CMake option `PythonQt_USE_RELEASE_PYTHON_FALLBACK`. Export build-tree binary include dir and install the configured header so `#include ` works for both build and install trees. Stop requiring downstreams to set the macro via compile definitions; users can still override by predefining `PYTHONQT_USE_RELEASE_PYTHON_FALLBACK`. --- CMakeLists.txt | 22 ++++++++++++++++-- src/PythonQtConfigure.h.in | 45 +++++++++++++++++++++++++++++++++++++ src/PythonQtPythonInclude.h | 2 ++ src/generate_configure_h.py | 37 ++++++++++++++++++++++++++++++ src/src.pro | 11 +++++++++ 5 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 src/PythonQtConfigure.h.in create mode 100644 src/generate_configure_h.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 9f129bcf6..9a94590b3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -267,6 +267,23 @@ foreach(qtlib ${qtlibs}) endif() endforeach() +#----------------------------------------------------------------------------- +# Configure header + +# Map the CMake option `PythonQt_USE_RELEASE_PYTHON_FALLBACK` (camelCase) +# to a plain variable used by the configured header. The public-facing +# preprocessor symbol remains `PYTHONQT_USE_RELEASE_PYTHON_FALLBACK`. +set(PYTHONQT_USE_RELEASE_PYTHON_FALLBACK ${PythonQt_USE_RELEASE_PYTHON_FALLBACK}) +configure_file( + src/PythonQtConfigure.h.in + ${CMAKE_CURRENT_BINARY_DIR}/src/PythonQtConfigure.h + ) +unset(PYTHONQT_USE_RELEASE_PYTHON_FALLBACK) + +list(APPEND headers + ${CMAKE_CURRENT_BINARY_DIR}/src/PythonQtConfigure.h + ) + #----------------------------------------------------------------------------- # Do wrapping pythonqt_wrap_cpp(gen_moc_sources ${moc_sources}) @@ -284,8 +301,8 @@ target_compile_definitions(PythonQt PRIVATE $<$:PYTHONQT_DEBUG> $<$:PYTHONQT_SUPPORT_NAME_PROPERTY> - PUBLIC - $<$:PYTHONQT_USE_RELEASE_PYTHON_FALLBACK> + # No need to export PYTHONQT_USE_RELEASE_PYTHON_FALLBACK publicly. the + # configured header handles consumers. ) target_compile_options(PythonQt PRIVATE @@ -295,6 +312,7 @@ target_compile_options(PythonQt PRIVATE target_include_directories(PythonQt PUBLIC $ + $ $ PRIVATE # Required for use of "QtCore/private/qmetaobjectbuilder_p.h" in "PythonQt.cpp" diff --git a/src/PythonQtConfigure.h.in b/src/PythonQtConfigure.h.in new file mode 100644 index 000000000..a8645abd7 --- /dev/null +++ b/src/PythonQtConfigure.h.in @@ -0,0 +1,45 @@ +/* + * + * Copyright (C) 2025 MeVis Medical Solutions AG All Rights Reserved. + * Copyright (C) 2025 Kitware, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29, + * 28359 Bremen, Germany or: + * + * http://www.mevis.de + * + */ + +#ifndef _PYTHONQTCONFIGURE_H +#define _PYTHONQTCONFIGURE_H + +// If the user has not pre-defined the macro, derive it from the CMake +// configure-time variable `PYTHONQT_USE_RELEASE_PYTHON_FALLBACK`, which +// mirrors the `PythonQt_USE_RELEASE_PYTHON_FALLBACK` (camelCase) CMake +// option. +#ifndef PYTHONQT_USE_RELEASE_PYTHON_FALLBACK +#cmakedefine PYTHONQT_USE_RELEASE_PYTHON_FALLBACK +#endif + +#endif diff --git a/src/PythonQtPythonInclude.h b/src/PythonQtPythonInclude.h index b88f51b26..663c28395 100644 --- a/src/PythonQtPythonInclude.h +++ b/src/PythonQtPythonInclude.h @@ -33,6 +33,8 @@ #ifndef __PythonQtPythonInclude_h #define __PythonQtPythonInclude_h +#include + // Undefine macros that features.h defines to avoid redefinition warning #ifdef _POSIX_C_SOURCE #undef _POSIX_C_SOURCE diff --git a/src/generate_configure_h.py b/src/generate_configure_h.py new file mode 100644 index 000000000..a0149a49e --- /dev/null +++ b/src/generate_configure_h.py @@ -0,0 +1,37 @@ +""" +Generate a C/C++ header from a CMake .in template for use with qmake builds. + +CMake processes .h.in files at configure time, replacing: + #cmakedefine VAR -> #define VAR (when VAR is ON/defined) + -> /* #undef VAR */ (when VAR is OFF/undefined) + +This script replaces all #cmakedefine directives with #define, which +matches the default PythonQt CMake option values (all defaults are ON). +""" + +import re +import sys + + +def main(): + if len(sys.argv) != 3: + print( + f"Usage: {sys.argv[0]} ", + file=sys.stderr, + ) + sys.exit(1) + + in_path, out_path = sys.argv[1], sys.argv[2] + + with open(in_path) as f: + content = f.read() + + # #cmakedefine VAR [rest] -> #define VAR [rest] + content = re.sub(r"^#cmakedefine\b", "#define", content, flags=re.MULTILINE) + + with open(out_path, "w") as f: + f.write(content) + + +if __name__ == "__main__": + main() diff --git a/src/src.pro b/src/src.pro index e7fba7578..bc4ab9f75 100644 --- a/src/src.pro +++ b/src/src.pro @@ -29,6 +29,17 @@ QT += widgets core-private INCLUDEPATH += $$PWD +# Generate PythonQtConfigure.h from template at qmake-configure time. +# The script replaces #cmakedefine directives (CMake syntax) with #define, +# enabling a pure qmake build without requiring a prior CMake run. +!exists($$PWD/PythonQtConfigure.h) { + win32: PYTHONQT_PYTHON = python + else: PYTHONQT_PYTHON = python3 + system($$PYTHONQT_PYTHON $$PWD/generate_configure_h.py \ + $$PWD/PythonQtConfigure.h.in \ + $$PWD/PythonQtConfigure.h) +} + macx { contains(QT_MAJOR_VERSION, 6) { QMAKE_APPLE_DEVICE_ARCHS = x86_64 arm64 From 4a36f7376e7dfa516c8e05de9ce214ef264be9f0 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Thu, 23 Oct 2025 12:52:46 -0400 Subject: [PATCH 15/30] cmake: Simplify build-system leveraging AUTOMOC capability --- CMakeLists.txt | 48 +++++++++++------------------------------------- 1 file changed, 11 insertions(+), 37 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a94590b3..d601b31b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -133,10 +133,6 @@ foreach(qt_component ${qt_required_components}) list(APPEND QT_LIBRARIES Qt5::${qt_component}) endforeach() -macro(pythonqt_wrap_cpp) - qt5_wrap_cpp(${ARGV}) -endmacro() - if(UNIX) find_package(OpenGL) if(OPENGL_FOUND) @@ -222,19 +218,6 @@ set(headers generated_cpp${generated_cpp_suffix}/PythonQt_QtBindings.h ) -#----------------------------------------------------------------------------- -# Headers that should run through moc - -set(moc_sources - src/PythonQt.h - src/PythonQtSignalReceiver.h - src/PythonQtStdDecorators.h - src/gui/PythonQtScriptingConsole.h - - generated_cpp${generated_cpp_suffix}/com_trolltech_qt_core_builtin/com_trolltech_qt_core_builtin0.h - generated_cpp${generated_cpp_suffix}/com_trolltech_qt_gui_builtin/com_trolltech_qt_gui_builtin0.h -) - #----------------------------------------------------------------------------- # Add extra sources @@ -255,11 +238,6 @@ foreach(qtlib ${qtlibs}) list(APPEND sources ${file_prefix}${index}.cpp) endif() - # Headers that should run through moc - if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${file_prefix}${index}.h) - list(APPEND moc_sources ${file_prefix}${index}.h) - endif() - endforeach() list(APPEND sources ${file_prefix}_init.cpp) @@ -284,19 +262,17 @@ list(APPEND headers ${CMAKE_CURRENT_BINARY_DIR}/src/PythonQtConfigure.h ) -#----------------------------------------------------------------------------- -# Do wrapping -pythonqt_wrap_cpp(gen_moc_sources ${moc_sources}) - #----------------------------------------------------------------------------- # Build the library -add_library(PythonQt SHARED - ${sources} - ${gen_moc_sources} - ) +add_library(PythonQt SHARED ${sources}) set_target_properties(PythonQt PROPERTIES DEFINE_SYMBOL PYTHONQT_EXPORTS) +set_target_properties(PythonQt + PROPERTIES + AUTOMOC TRUE + ) + target_compile_definitions(PythonQt PRIVATE $<$:PYTHONQT_DEBUG> @@ -352,18 +328,11 @@ if(BUILD_TESTING) tests/PythonQtTests.h ) - pythonqt_wrap_cpp(test_sources - tests/PythonQtTests.h - ) - if(PythonQt_Wrap_QtCore) list(APPEND test_sources tests/PythonQtTestCleanup.cpp tests/PythonQtTestCleanup.h ) - pythonqt_wrap_cpp(test_sources - tests/PythonQtTestCleanup.h - ) set_property(SOURCE tests/PythonQtTestMain.cpp APPEND PROPERTY COMPILE_DEFINITIONS "PythonQt_Wrap_QtCore") endif() @@ -377,6 +346,11 @@ if(BUILD_TESTING) target_link_libraries(PythonQtCppTests PythonQt) + set_target_properties(PythonQtCppTests + PROPERTIES + AUTOMOC TRUE + ) + target_compile_definitions(PythonQtCppTests PRIVATE $<$:PYTHONQT_SUPPORT_NAME_PROPERTY> From c0aaaeefc6e118b3b927898277a0d1b7aaf42ddd Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Thu, 23 Oct 2025 21:37:39 -0400 Subject: [PATCH 16/30] cmake/tests: fix PythonQt_QtAll exports and QtCore wrap handling make PythonQt_QtAll export macro treat both PYTHONQT_QTALL_EXPORTS and PYTHONQT_EXPORTS as build context Co-authored-by: James Butler --- extensions/PythonQt_QtAll/PythonQt_QtAll.h | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/extensions/PythonQt_QtAll/PythonQt_QtAll.h b/extensions/PythonQt_QtAll/PythonQt_QtAll.h index 381193960..6021e0aa9 100644 --- a/extensions/PythonQt_QtAll/PythonQt_QtAll.h +++ b/extensions/PythonQt_QtAll/PythonQt_QtAll.h @@ -33,18 +33,27 @@ * */ -#ifdef WIN32 - #ifdef PYTHONQT_QTALL_EXPORTS +// Export macro for the PythonQt_QtAll symbols. +// qmake builds define PYTHONQT_QTALL_EXPORTS for the dedicated QtAll DLL, +// while CMake builds compile this source into the PythonQt target which defines +// PYTHONQT_EXPORTS. Treat either define as "building" to avoid dllimport on +// in-target function definitions. +#if defined(WIN32) + #if defined(PYTHONQT_QTALL_EXPORTS) || defined(PYTHONQT_EXPORTS) #define PYTHONQT_QTALL_EXPORT __declspec(dllexport) #else #define PYTHONQT_QTALL_EXPORT __declspec(dllimport) #endif #else - #define PYTHONQT_QTALL_EXPORT + #if defined(PYTHONQT_QTALL_EXPORTS) || defined(PYTHONQT_EXPORTS) + #define PYTHONQT_QTALL_EXPORT __attribute__((__visibility__("default"))) + #else + #define PYTHONQT_QTALL_EXPORT + #endif #endif namespace PythonQt_QtAll { -//! initialize the Qt binding +//! Initialize the Qt bindings enabled at configuration time PYTHONQT_QTALL_EXPORT void init(); } From 105f3ffa708233333dfd55491dd87f55cd673176 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Thu, 23 Oct 2025 21:40:15 -0400 Subject: [PATCH 17/30] cmake: Prefer PythonQt_QtAll and remove PythonQt_QtBindings --- CMakeLists.txt | 9 ++- generated_cpp_515/PythonQt_QtBindings.cpp | 73 ----------------------- generated_cpp_515/PythonQt_QtBindings.h | 10 ---- tests/PythonQtTestCleanup.cpp | 4 +- 4 files changed, 8 insertions(+), 88 deletions(-) delete mode 100644 generated_cpp_515/PythonQt_QtBindings.cpp delete mode 100644 generated_cpp_515/PythonQt_QtBindings.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d601b31b8..05ab94c9e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -176,7 +176,7 @@ set(sources src/PythonQtThreadSupport.cpp src/gui/PythonQtScriptingConsole.cpp - generated_cpp${generated_cpp_suffix}/PythonQt_QtBindings.cpp + extensions/PythonQt_QtAll/PythonQt_QtAll.cpp generated_cpp${generated_cpp_suffix}/com_trolltech_qt_core_builtin/com_trolltech_qt_core_builtin0.cpp generated_cpp${generated_cpp_suffix}/com_trolltech_qt_core_builtin/com_trolltech_qt_core_builtin_init.cpp @@ -215,7 +215,7 @@ set(headers src/PythonQtUtils.h src/PythonQtVariants.h src/PythonQtPythonInclude.h - generated_cpp${generated_cpp_suffix}/PythonQt_QtBindings.h + extensions/PythonQt_QtAll/PythonQt_QtAll.h ) #----------------------------------------------------------------------------- @@ -227,7 +227,9 @@ foreach(qtlib ${qtlibs}) if (${PythonQt_Wrap_Qt${qt_wrapped_lib}}) - ADD_DEFINITIONS(-DPYTHONQT_WRAP_Qt${qt_wrapped_lib}) + # Variable expected by PythonQt_QtAll.cpp + string(TOUPPER ${qt_wrapped_lib} qt_wrapped_lib_uppercase) + ADD_DEFINITIONS(-DPYTHONQT_WITH_${qt_wrapped_lib_uppercase}) set(file_prefix generated_cpp${generated_cpp_suffix}/com_trolltech_qt_${qt_wrapped_lib}/com_trolltech_qt_${qt_wrapped_lib}) @@ -288,6 +290,7 @@ target_compile_options(PythonQt PRIVATE target_include_directories(PythonQt PUBLIC $ + $ $ $ PRIVATE diff --git a/generated_cpp_515/PythonQt_QtBindings.cpp b/generated_cpp_515/PythonQt_QtBindings.cpp deleted file mode 100644 index c6f8d4b09..000000000 --- a/generated_cpp_515/PythonQt_QtBindings.cpp +++ /dev/null @@ -1,73 +0,0 @@ - -#include "PythonQt_QtBindings.h" - -#include "PythonQt.h" - -void PythonQt_init_QtGui(PyObject*); -void PythonQt_init_QtSvg(PyObject*); -void PythonQt_init_QtSql(PyObject*); -void PythonQt_init_QtNetwork(PyObject*); -void PythonQt_init_QtCore(PyObject*); -void PythonQt_init_QtWebKit(PyObject*); -void PythonQt_init_QtOpenGL(PyObject*); -void PythonQt_init_QtQml(PyObject*); -void PythonQt_init_QtQuick(PyObject*); -void PythonQt_init_QtXml(PyObject*); -void PythonQt_init_QtXmlPatterns(PyObject*); -void PythonQt_init_QtUiTools(PyObject*); -void PythonQt_init_QtMultimedia(PyObject*); - -PYTHONQT_EXPORT void PythonQt_init_QtBindings() - { - #ifdef PYTHONQT_WRAP_Qtcore - PythonQt_init_QtCore(0); - #endif - - #ifdef PYTHONQT_WRAP_Qtgui - PythonQt_init_QtGui(0); - #endif - - #ifdef PYTHONQT_WRAP_Qtnetwork - PythonQt_init_QtNetwork(0); - #endif - - #ifdef PYTHONQT_WRAP_Qtopengl - PythonQt_init_QtOpenGL(0); - #endif - - #ifdef PYTHONQT_WRAP_Qtqml - PythonQt_init_QtQml(0); - #endif - - #ifdef PYTHONQT_WRAP_Qtquick - PythonQt_init_QtQuick(0); - #endif - - #ifdef PYTHONQT_WRAP_Qtsql - PythonQt_init_QtSql(0); - #endif - - #ifdef PYTHONQT_WRAP_Qtsvg - PythonQt_init_QtSvg(0); - #endif - - #ifdef PYTHONQT_WRAP_Qtuitools - PythonQt_init_QtUiTools(0); - #endif - - #ifdef PYTHONQT_WRAP_Qtmultimedia - PythonQt_init_QtMultimedia(0); - #endif - - #ifdef PYTHONQT_WRAP_Qtwebkit - PythonQt_init_QtWebKit(0); - #endif - - #ifdef PYTHONQT_WRAP_Qtxml - PythonQt_init_QtXml(0); - #endif - - #ifdef PYTHONQT_WRAP_Qtxmlpatterns - PythonQt_init_QtXmlPatterns(0); - #endif - }; diff --git a/generated_cpp_515/PythonQt_QtBindings.h b/generated_cpp_515/PythonQt_QtBindings.h deleted file mode 100644 index 03e96aed8..000000000 --- a/generated_cpp_515/PythonQt_QtBindings.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _PYTHONQT_QTBINDINGS_H -#define _PYTHONQT_QTBINDINGS_H - -#include "PythonQtSystem.h" - -/// Initialize Qt bindings enabled at configuration time -PYTHONQT_EXPORT void PythonQt_init_QtBindings(); - -#endif - diff --git a/tests/PythonQtTestCleanup.cpp b/tests/PythonQtTestCleanup.cpp index 2459cf6a3..862931215 100644 --- a/tests/PythonQtTestCleanup.cpp +++ b/tests/PythonQtTestCleanup.cpp @@ -1,6 +1,6 @@ #include "PythonQtTestCleanup.h" #include "PythonQt.h" -#include "PythonQt_QtBindings.h" +#include "PythonQt_QtAll.h" void PythonQtTestCleanup::initTestCase() {} @@ -11,7 +11,7 @@ void PythonQtTestCleanup::init() // Initialize before each test PythonQt::init(PythonQt::IgnoreSiteModule); - PythonQt_init_QtBindings(); + PythonQt_QtAll::init(); _helper = new PythonQtTestCleanupHelper(); PythonQtObjectPtr main = PythonQt::self()->getMainModule(); From f236d553e38141d577f64e6b708afbb427ed6e51 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Thu, 30 Oct 2025 01:46:50 -0400 Subject: [PATCH 18/30] cmake(generator): Modernize generator build-system - Leverages automatic execution of MOC and RCC. - Removes obsolete install rules for `build_*.txt` and `typesystem_*.xml`. - Uses "usage requirements" and aligns source lists with `parser/rxx.pro`, `simplecpp/simplecpp.pri`, `generator.pri`, and `generator.pro`. --- generator/CMakeLists.txt | 140 ++++++++++++--------------------------- 1 file changed, 43 insertions(+), 97 deletions(-) diff --git a/generator/CMakeLists.txt b/generator/CMakeLists.txt index 0801c58c0..fc4052f2f 100644 --- a/generator/CMakeLists.txt +++ b/generator/CMakeLists.txt @@ -1,37 +1,29 @@ -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 3.20.6) -#----------------------------------------------------------------------------- -project(PythonQtGenerator) -#----------------------------------------------------------------------------- - -include(CTestUseLaunchers OPTIONAL) +project(PythonQtGenerator LANGUAGES CXX) -#----------------------------------------------------------------------------- +#---------------------------------------------------------------------------- # Setup Qt -set(minimum_required_qt_version "4.6.2") - -find_package(Qt4) +# Set PythonQtGenerator_QT_VERSION +set(PythonQtGenerator_QT_VERSION 5) -if(QT4_FOUND) +set(minimum_required_qt5_version "5.15.0") +set(minimum_required_qt_version ${minimum_required_qt${PythonQtGenerator_QT_VERSION}_version}) - set(found_qt_version ${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}.${QT_VERSION_PATCH}) +set(qt_required_components Core Xml) - if(${found_qt_version} VERSION_LESS ${minimum_required_qt_version}) - message(FATAL_ERROR "error: PythonQt requires Qt >= ${minimum_required_qt_version} -- you cannot use Qt ${found_qt_version}.") - endif() +message(STATUS "${PROJECT_NAME}: Required Qt${PythonQtGenerator_QT_VERSION} components [${qt_required_components}]") - set(QT_USE_QTXML ON) - - include(${QT_USE_FILE}) -else() - message(FATAL_ERROR "error: Qt4 was not found on your system. You probably need to set the QT_QMAKE_EXECUTABLE variable") -endif() +# Requirements +find_package(Qt${PythonQtGenerator_QT_VERSION} ${minimum_required_qt_version} + COMPONENTS ${qt_required_components} REQUIRED) #----------------------------------------------------------------------------- # Sources set(sources + # Based of parser/rxx.pro parser/ast.cpp parser/binder.cpp parser/class_compiler.cpp @@ -51,108 +43,62 @@ set(sources parser/type_compiler.cpp parser/visitor.cpp + # Based of simplecpp/simplecpp.pri + simplecpp/simplecpp.cpp + + # Based of generator.pri abstractmetabuilder.cpp abstractmetalang.cpp asttoxml.cpp customtypes.cpp fileout.cpp generator.cpp + generator.qrc generatorset.cpp - generatorsetqtscript.cpp main.cpp metajava.cpp - metaqtscriptbuilder.cpp - metaqtscript.cpp prigenerator.cpp reporthandler.cpp + typeparser.cpp + typesystem.cpp + + # Based of generator.pro + generatorsetqtscript.cpp + metaqtscriptbuilder.cpp + metaqtscript.cpp setupgenerator.cpp shellgenerator.cpp shellheadergenerator.cpp shellimplgenerator.cpp - typeparser.cpp - typesystem.cpp ) -#----------------------------------------------------------------------------- -# List headers. This list is used for the install command. +add_executable(${PROJECT_NAME} ${sources}) -set(headers +set_target_properties(${PROJECT_NAME} + PROPERTIES + AUTOMOC TRUE + AUTORCC TRUE ) -#----------------------------------------------------------------------------- -# Headers that should run through moc - -set(moc_sources - fileout.h - generator.h - generatorset.h - generatorsetqtscript.h - prigenerator.h - setupgenerator.h - shellgenerator.h - shellheadergenerator.h - shellimplgenerator.h +target_include_directories(${PROJECT_NAME} + PUBLIC + $ + $ + $ ) -#----------------------------------------------------------------------------- -# UI files - -set(ui_sources ) - -#----------------------------------------------------------------------------- -# Resources - -set(qrc_sources - generator.qrc +target_link_libraries(${PROJECT_NAME} + PUBLIC + Qt::Core + Qt::Xml ) -#----------------------------------------------------------------------------- -# Do wrapping -qt4_wrap_cpp(gen_moc_sources ${moc_sources}) -qt4_wrap_ui(gen_ui_sources ${ui_sources}) -qt4_add_resources(gen_qrc_sources ${qrc_sources}) - -#----------------------------------------------------------------------------- -# Copy file expected by the generator and specify install rules - -file(GLOB files_to_copy RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "build_*.txt" "typesystem_*.xml") -list(APPEND files_to_copy qtscript_masterinclude.h parser/rpp/pp-qt-configuration) -foreach(file ${files_to_copy}) - configure_file( - ${file} - ${CMAKE_CURRENT_BINARY_DIR}/${file} - COPYONLY - ) - get_filename_component(destination_dir ${file} PATH) - install(FILES ${file} DESTINATION bin/${destination_dir}) -endforeach() - -#----------------------------------------------------------------------------- -# Build the library - -SOURCE_GROUP("Resources" FILES - ${qrc_sources} - ${ui_sources} - ${files_to_copy} +target_compile_definitions(${PROJECT_NAME} + PRIVATE + RXX_ALLOCATOR_INIT_0 # Based of parser/rxx.pro + QT_NO_CAST_TO_ASCII # Based of generator.pro ) -include_directories( - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/parser - ${CMAKE_CURRENT_SOURCE_DIR}/parser/rpp - ) - -add_definitions(-DRXX_ALLOCATOR_INIT_0) - -add_executable(${PROJECT_NAME} - ${sources} - ${gen_moc_sources} - ${gen_ui_sources} - ${gen_qrc_sources} -) - -target_link_libraries(${PROJECT_NAME} ${QT_LIBRARIES}) - #----------------------------------------------------------------------------- # Install library (on windows, put the dll in 'bin' and the archive in 'lib') From 00254c9f10b2c0adbdd993675931802e8d43cf58 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Thu, 30 Oct 2025 02:17:16 -0400 Subject: [PATCH 19/30] cmake: Remove obsolete comment --- CMakeLists.txt | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 05ab94c9e..8cc92ec62 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,3 @@ -#----------------------------------------------------------------------------- -# NOTE: The CMake files have been contributed to PythonQt and have not been tested with the current -# PythonQt version. They have not yet been updated to support Qt 5 and/or Python 3. -# -# If you are not a CMake expert, you should better use the provided qmake profiles. -#----------------------------------------------------------------------------- cmake_minimum_required(VERSION 3.20.6) @@ -185,7 +179,7 @@ set(sources ) #----------------------------------------------------------------------------- -# List headers. This is list is used for the install command. +# List headers. This list is used for the install command. set(headers src/PythonQtBoolResult.h From 58d1fa0602578b0487e6be13c1e0264d282445c7 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Thu, 30 Oct 2025 08:47:17 -0400 Subject: [PATCH 20/30] cmake: Introduce PythonQt_GENERATED_PATH variable --- CMakeLists.txt | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8cc92ec62..27b0ab6ee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -135,13 +135,18 @@ if(UNIX) endif() #----------------------------------------------------------------------------- -# The variable "generated_cpp_suffix" allows to conditionnally compile the generated wrappers -# associated with the Qt version being used. - -if("${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}" VERSION_GREATER_EQUAL "5.15") - set(generated_cpp_suffix "_515") -else() - message(FATAL_ERROR "Generated wrappers only available for Qt >= 5.15 (found ${QT_VERSION}).") +# Pre-generated wrappers default to Qt 5.15 set (generated_cpp_515). Users may override. +set(generated_cpp_suffix "_515") +set(_default_generated_path "${CMAKE_CURRENT_SOURCE_DIR}/generated_cpp${generated_cpp_suffix}") + +set(PythonQt_GENERATED_PATH "${_default_generated_path}" + CACHE PATH "Directory containing pre-generated PythonQt Qt wrappers for Qt ${QT_VERSION_MAJOR}.${QT_VERSION_MINOR} (e.g., generated_cpp_515)") + +if(NOT IS_DIRECTORY "${PythonQt_GENERATED_PATH}") + message(FATAL_ERROR + "PythonQt: missing generated wrapper sources for Qt ${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}.\n" + "Expected: ${PythonQt_GENERATED_PATH}\n" + "Hint: pass -DPythonQt_GENERATED_PATH:PATH=/path/to/generated_cpp") endif() #----------------------------------------------------------------------------- @@ -172,10 +177,10 @@ set(sources extensions/PythonQt_QtAll/PythonQt_QtAll.cpp - generated_cpp${generated_cpp_suffix}/com_trolltech_qt_core_builtin/com_trolltech_qt_core_builtin0.cpp - generated_cpp${generated_cpp_suffix}/com_trolltech_qt_core_builtin/com_trolltech_qt_core_builtin_init.cpp - generated_cpp${generated_cpp_suffix}/com_trolltech_qt_gui_builtin/com_trolltech_qt_gui_builtin0.cpp - generated_cpp${generated_cpp_suffix}/com_trolltech_qt_gui_builtin/com_trolltech_qt_gui_builtin_init.cpp + ${PythonQt_GENERATED_PATH}/com_trolltech_qt_core_builtin/com_trolltech_qt_core_builtin0.cpp + ${PythonQt_GENERATED_PATH}/com_trolltech_qt_core_builtin/com_trolltech_qt_core_builtin_init.cpp + ${PythonQt_GENERATED_PATH}/com_trolltech_qt_gui_builtin/com_trolltech_qt_gui_builtin0.cpp + ${PythonQt_GENERATED_PATH}/com_trolltech_qt_gui_builtin/com_trolltech_qt_gui_builtin_init.cpp ) #----------------------------------------------------------------------------- @@ -225,18 +230,18 @@ foreach(qtlib ${qtlibs}) string(TOUPPER ${qt_wrapped_lib} qt_wrapped_lib_uppercase) ADD_DEFINITIONS(-DPYTHONQT_WITH_${qt_wrapped_lib_uppercase}) - set(file_prefix generated_cpp${generated_cpp_suffix}/com_trolltech_qt_${qt_wrapped_lib}/com_trolltech_qt_${qt_wrapped_lib}) + set(file_prefix com_trolltech_qt_${qt_wrapped_lib}/com_trolltech_qt_${qt_wrapped_lib}) foreach(index RANGE 0 12) # Source files - if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${file_prefix}${index}.cpp) - list(APPEND sources ${file_prefix}${index}.cpp) + if(EXISTS ${PythonQt_GENERATED_PATH}/${file_prefix}${index}.cpp) + list(APPEND sources ${PythonQt_GENERATED_PATH}/${file_prefix}${index}.cpp) endif() endforeach() - list(APPEND sources ${file_prefix}_init.cpp) + list(APPEND sources ${PythonQt_GENERATED_PATH}/${file_prefix}_init.cpp) endif() endforeach() @@ -338,7 +343,7 @@ if(BUILD_TESTING) target_include_directories(PythonQtCppTests PRIVATE - $<$:${CMAKE_CURRENT_SOURCE_DIR}/generated_cpp${generated_cpp_suffix}> + $<$:${PythonQt_GENERATED_PATH}> ) target_link_libraries(PythonQtCppTests PythonQt) From c3349705304c9796d816169d545da3ec0c4ab03d Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Fri, 31 Oct 2025 00:45:31 -0400 Subject: [PATCH 21/30] cmake: Prefer using CorePrivate Qt target MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This removes the use of version-specific Qt variable like `Qt5Core_PRIVATE_INCLUDE_DIRS` and instead relies on CMake’s imported targets for private headers. --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 27b0ab6ee..7100620e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -292,15 +292,15 @@ target_include_directories(PythonQt $ $ $ - PRIVATE - # Required for use of "QtCore/private/qmetaobjectbuilder_p.h" in "PythonQt.cpp" - ${Qt5Core_PRIVATE_INCLUDE_DIRS} ) target_link_libraries(PythonQt PUBLIC Python3::Python ${QT_LIBRARIES} + PRIVATE + # Required for use of "QtCore/private/qmetaobjectbuilder_p.h" in "PythonQt.cpp" + Qt${PythonQt_QT_VERSION}::CorePrivate ) #----------------------------------------------------------------------------- From a37e5c91a29e6624e9d179df0eed31684c6b4762 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Fri, 31 Oct 2025 00:46:29 -0400 Subject: [PATCH 22/30] cmake: Add Qt6 support for building PythonQt and PythonQtGenerator - Add configurable Qt major version (5 or 6) with sensible default (Qt6 if Qt6_DIR is defined, otherwise Qt5). - Require Qt >= 5.15.0 or Qt >= 6.9.0. - Switch component discovery and linking to `Qt${MAJOR}::...` targets. - Define QT_VERSION_MAJOR/MINOR from the found package. - Make pre-generated wrappers default only for Qt5 (generated_cpp_515); for Qt6, default to unset (wrappers must be generated). --- CMakeLists.txt | 31 +++++++++++++++++++++++-------- generator/CMakeLists.txt | 16 +++++++++++++--- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7100620e0..6a00ebe41 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,16 +6,24 @@ project(PythonQt) #---------------------------------------------------------------------------- # Qt version +set(_default_qt_major_version 5) +if(DEFINED Qt6_DIR) + set(_default_qt_major_version 6) +endif() + # Set PythonQt_QT_VERSION -set(PythonQt_QT_VERSION 5) +set(PythonQt_QT_VERSION ${_default_qt_major_version} CACHE STRING "Qt major version (5 or 6)") +set_property(CACHE PythonQt_QT_VERSION PROPERTY STRINGS "5" "6") +if(NOT "${PythonQt_QT_VERSION}" MATCHES "^(5|6)$") + message(FATAL_ERROR "error: PythonQt_QT_VERSION must be 5 or 6.") +endif() # Requirements set(minimum_required_qt5_version "5.15.0") +set(minimum_required_qt6_version "6.9.0") set(minimum_required_qt_version ${minimum_required_qt${PythonQt_QT_VERSION}_version}) -find_package(Qt5 ${minimum_required_qt_version} QUIET) -set(QT_VERSION_MAJOR ${Qt5_VERSION_MAJOR}) -set(QT_VERSION_MINOR ${Qt5_VERSION_MINOR}) +find_package(Qt${PythonQt_QT_VERSION} ${minimum_required_qt_version} QUIET) #---------------------------------------------------------------------------- # Qt components @@ -120,11 +128,14 @@ endif() list(REMOVE_DUPLICATES qt_required_components) message(STATUS "${PROJECT_NAME}: Required Qt components [${qt_required_components}]") -find_package(Qt5 ${minimum_required_qt_version} COMPONENTS ${qt_required_components} REQUIRED) +find_package(Qt${PythonQt_QT_VERSION} ${minimum_required_qt_version} COMPONENTS ${qt_required_components} REQUIRED) + +set(QT_VERSION_MAJOR ${Qt${PythonQt_QT_VERSION}_VERSION_MAJOR}) +set(QT_VERSION_MINOR ${Qt${PythonQt_QT_VERSION}_VERSION_MINOR}) set(QT_LIBRARIES ) foreach(qt_component ${qt_required_components}) - list(APPEND QT_LIBRARIES Qt5::${qt_component}) + list(APPEND QT_LIBRARIES Qt${PythonQt_QT_VERSION}::${qt_component}) endforeach() if(UNIX) @@ -136,8 +147,12 @@ endif() #----------------------------------------------------------------------------- # Pre-generated wrappers default to Qt 5.15 set (generated_cpp_515). Users may override. -set(generated_cpp_suffix "_515") -set(_default_generated_path "${CMAKE_CURRENT_SOURCE_DIR}/generated_cpp${generated_cpp_suffix}") +if(PythonQt_QT_VERSION VERSION_EQUAL "5") + set(generated_cpp_suffix "_515") + set(_default_generated_path "${CMAKE_CURRENT_SOURCE_DIR}/generated_cpp${generated_cpp_suffix}") +else() + set(_default_generated_path "PythonQt_GENERATED_PATH-NOTFOUND") +endif() set(PythonQt_GENERATED_PATH "${_default_generated_path}" CACHE PATH "Directory containing pre-generated PythonQt Qt wrappers for Qt ${QT_VERSION_MAJOR}.${QT_VERSION_MINOR} (e.g., generated_cpp_515)") diff --git a/generator/CMakeLists.txt b/generator/CMakeLists.txt index fc4052f2f..5a014d323 100644 --- a/generator/CMakeLists.txt +++ b/generator/CMakeLists.txt @@ -5,10 +5,20 @@ project(PythonQtGenerator LANGUAGES CXX) #---------------------------------------------------------------------------- # Setup Qt +set(_default_qt_major_version 5) +if(DEFINED Qt6_DIR) + set(_default_qt_major_version 6) +endif() + # Set PythonQtGenerator_QT_VERSION -set(PythonQtGenerator_QT_VERSION 5) +set(PythonQtGenerator_QT_VERSION ${_default_qt_major_version} CACHE STRING "Qt major version (5 or 6)") +set_property(CACHE PythonQtGenerator_QT_VERSION PROPERTY STRINGS "5" "6") +if(NOT "${PythonQtGenerator_QT_VERSION}" MATCHES "^(5|6)$") + message(FATAL_ERROR "error: PythonQtGenerator_QT_VERSION must be 5 or 6.") +endif() set(minimum_required_qt5_version "5.15.0") +set(minimum_required_qt6_version "6.9.0") set(minimum_required_qt_version ${minimum_required_qt${PythonQtGenerator_QT_VERSION}_version}) set(qt_required_components Core Xml) @@ -89,8 +99,8 @@ target_include_directories(${PROJECT_NAME} target_link_libraries(${PROJECT_NAME} PUBLIC - Qt::Core - Qt::Xml + Qt${PythonQtGenerator_QT_VERSION}::Core + Qt${PythonQtGenerator_QT_VERSION}::Xml ) target_compile_definitions(${PROJECT_NAME} From 50bcd52f036ddd8068368fcff7ea0ac9d4b2bd09 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Thu, 6 Nov 2025 04:46:04 -0500 Subject: [PATCH 23/30] cmake: Simplify mapping of Qt wrapped library to component This simplifies the mapping of Qt wrapped libraries to their components by removing the redundant version-specific prefix 'qt5' from variable names. --- CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6a00ebe41..6faeaff47 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,9 +76,9 @@ endif() set(qtlib_to_wraplib_Widgets gui) set(qtlib_to_wraplib_WebKitWidgets webkit) -set(qt5_wrapped_lib_depends_gui Multimedia PrintSupport) -set(qt5_wrapped_lib_depends_multimedia MultimediaWidgets) -set(qt5_wrapped_lib_depends_quick QuickWidgets) +set(qt_wrapped_lib_depends_gui Multimedia PrintSupport) +set(qt_wrapped_lib_depends_multimedia MultimediaWidgets) +set(qt_wrapped_lib_depends_quick QuickWidgets) foreach(qtlib ${qtlibs}) string(TOLOWER ${qtlib} qtlib_lowercase) @@ -119,7 +119,7 @@ set(qt_required_components Core Widgets) foreach(qtlib ${qtlibs}) set(qt_wrapped_lib ${qtlib_to_wraplib_${qtlib}}) if(${PythonQt_Wrap_Qt${qt_wrapped_lib}}) - list(APPEND qt_required_components ${qtlib} ${qt${PythonQt_QT_VERSION}_wrapped_lib_depends_${qt_wrapped_lib}}) + list(APPEND qt_required_components ${qtlib} ${qt_wrapped_lib_depends_${qt_wrapped_lib}}) endif() endforeach() if(BUILD_TESTING) From 707917213cc897662c7fcfe1e7a36de72dcb12cf Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Thu, 6 Nov 2025 04:46:46 -0500 Subject: [PATCH 24/30] cmake: Update Qt wrapped library to component mapping for Qt6 This updates the mapping of Qt wrapped libraries to components to support Qt6. Additional dependencies for certain components are included when PythonQt_QT_VERSION is 6. --- CMakeLists.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6faeaff47..a4dad8af9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -77,8 +77,19 @@ set(qtlib_to_wraplib_Widgets gui) set(qtlib_to_wraplib_WebKitWidgets webkit) set(qt_wrapped_lib_depends_gui Multimedia PrintSupport) +if(PythonQt_QT_VERSION VERSION_EQUAL "6") + list(APPEND qt_wrapped_lib_depends_gui Widgets OpenGL) +endif() set(qt_wrapped_lib_depends_multimedia MultimediaWidgets) set(qt_wrapped_lib_depends_quick QuickWidgets) +set(qt_wrapped_lib_depends_svg ) +if(PythonQt_QT_VERSION VERSION_EQUAL "6") + list(APPEND qt_wrapped_lib_depends_svg SvgWidgets) +endif() +set(qt_wrapped_lib_depends_webkit ) +if(PythonQt_QT_VERSION VERSION_EQUAL "6") + list(APPEND qt_wrapped_lib_depends_webkit WebKitWidgets) +endif() foreach(qtlib ${qtlibs}) string(TOLOWER ${qtlib} qtlib_lowercase) From 062f26ad2f076b2b80ac585253d5119f18bf5fc7 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Thu, 6 Nov 2025 04:47:52 -0500 Subject: [PATCH 25/30] cmake: Address build error by partially reverting AUTOMOC changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Partially reverts dd82ba4b ("[commontk] cmake: Simplify build-system leveraging AUTOMOC capability", 2025-10-23) to fix a build error reported when AUTOMOC merges all `moc_*.cpp` into one Translation Unit (TU) (`_autogen/mocs_compilation*.cpp`). This change includes: - Reverting to manual specification of moc sources. - Disabling AUTOMOC for specified sources to avoid QMetaTypeId specialization conflicts. This fixes the following error: ``` In file included from /path/to/Support/Qt/6.9.1/gcc_64/include/QtCore/qvariant.h:10, from /path/to/Support/Qt/6.9.1/gcc_64/include/QtCore/qmetaobject.h:10, from /path/to/Support/Qt/6.9.1/gcc_64/include/QtCore/QMetaMethod:1, from /path/to/Projects/PythonQt-CTK/src/PythonQtUtils.h:49, from /path/to/Projects/PythonQt-CTK/src/PythonQt.h:46, from /path/to/Projects/PythonQt-CTK-cmake-Qt6-Release/PythonQt_autogen/CRAGYDUSE3/../../../CTK-Qt6-build/PythonQtGenerator-output-6.9.1/generated_cpp/com_trolltech_qt_core/com_trolltech_qt_core0.h:1, from /path/to/Projects/PythonQt-CTK-cmake-Qt6-Release/PythonQt_autogen/CRAGYDUSE3/moc_com_trolltech_qt_core0.cpp:9, from /path/to/Projects/PythonQt-CTK-cmake-Qt6-Release/PythonQt_autogen/mocs_compilation.cpp:2: /path/to/Support/Qt/6.9.1/gcc_64/include/QtPrintSupport/qprintengine.h:12:1: error: specialization of ‘QMetaTypeId’ after instantiation 12 | Q_DECLARE_METATYPE(QMarginsF) | ^~~~~~~~~~~~~~~~~~ /path/to/Support/Qt/6.9.1/gcc_64/include/QtPrintSupport/qprintengine.h:12:1: error: redefinition of ‘struct QMetaTypeId’ /path/to/Support/Qt/6.9.1/gcc_64/include/QtCore/qmetatype.h:1232:8: note: previous definition of ‘struct QMetaTypeId’ ``` --- CMakeLists.txt | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index a4dad8af9..dec0b4d50 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -243,6 +243,12 @@ set(headers extensions/PythonQt_QtAll/PythonQt_QtAll.h ) +#----------------------------------------------------------------------------- +# Headers that should run through moc + +set(moc_sources +) + #----------------------------------------------------------------------------- # Add extra sources @@ -265,6 +271,11 @@ foreach(qtlib ${qtlibs}) list(APPEND sources ${PythonQt_GENERATED_PATH}/${file_prefix}${index}.cpp) endif() + # Headers that should run through moc + if(EXISTS ${PythonQt_GENERATED_PATH}/${file_prefix}${index}.h) + list(APPEND moc_sources ${PythonQt_GENERATED_PATH}/${file_prefix}${index}.h) + endif() + endforeach() list(APPEND sources ${PythonQt_GENERATED_PATH}/${file_prefix}_init.cpp) @@ -272,6 +283,10 @@ foreach(qtlib ${qtlibs}) endif() endforeach() +#----------------------------------------------------------------------------- +# Do wrapping +qt_wrap_cpp(sources ${moc_sources}) + #----------------------------------------------------------------------------- # Configure header @@ -300,6 +315,11 @@ set_target_properties(PythonQt AUTOMOC TRUE ) +# Disable AUTOMOC for specified moc sources to avoid QMetaTypeId specialization conflicts. +foreach(moc_source IN LISTS moc_sources) + set_property(SOURCE ${moc_source} PROPERTY SKIP_AUTOMOC ON) +endforeach() + target_compile_definitions(PythonQt PRIVATE $<$:PYTHONQT_DEBUG> From d7d15767a7377fc96943121c75352ad7c7fd250f Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Sun, 9 Nov 2025 00:52:50 -0500 Subject: [PATCH 26/30] cmake: Relax minimum required Qt version to support Ubuntu 24.04 This changes the minimum required Qt6 version from 6.9.0 to 6.4.0 to ensure compatibility with Ubuntu 24.04, which ships with Qt 6.4.2. --- CMakeLists.txt | 2 +- generator/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dec0b4d50..1e3f02aff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ endif() # Requirements set(minimum_required_qt5_version "5.15.0") -set(minimum_required_qt6_version "6.9.0") +set(minimum_required_qt6_version "6.4.0") set(minimum_required_qt_version ${minimum_required_qt${PythonQt_QT_VERSION}_version}) find_package(Qt${PythonQt_QT_VERSION} ${minimum_required_qt_version} QUIET) diff --git a/generator/CMakeLists.txt b/generator/CMakeLists.txt index 5a014d323..2aa573c6b 100644 --- a/generator/CMakeLists.txt +++ b/generator/CMakeLists.txt @@ -18,7 +18,7 @@ if(NOT "${PythonQtGenerator_QT_VERSION}" MATCHES "^(5|6)$") endif() set(minimum_required_qt5_version "5.15.0") -set(minimum_required_qt6_version "6.9.0") +set(minimum_required_qt6_version "6.4.0") set(minimum_required_qt_version ${minimum_required_qt${PythonQtGenerator_QT_VERSION}_version}) set(qt_required_components Core Xml) From d299be1970dd7bda785318206744fe876acc4735 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Sun, 9 Nov 2025 19:13:36 -0500 Subject: [PATCH 27/30] cmake: Suggest XmlPatterns as a build option only with Qt 5 Since XmlPatterns was removed in Qt 6, it should not be considered. See https://doc.qt.io/qt-6/whatsnew60.html#removed-modules-in-qt-6-0 --- CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e3f02aff..09c7717b9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,8 +39,13 @@ set(qtlibs Multimedia UiTools Xml - XmlPatterns ) +# XmlPatterns is removed from Qt 6 +if(PythonQt_QT_VERSION VERSION_EQUAL "5") + list(APPEND qtlibs + XmlPatterns + ) +endif() #----------------------------------------------------------------------------- # Python libraries From 1da46c75e35ef182773233e36db4feddf62ec319 Mon Sep 17 00:00:00 2001 From: Bernhard Froehler Date: Wed, 12 Nov 2025 16:01:19 +0100 Subject: [PATCH 28/30] cmake: Add 6.10 support (additional CorePrivate component) --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 09c7717b9..559aa495a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -141,6 +141,9 @@ endforeach() if(BUILD_TESTING) list(APPEND qt_required_components Test) endif() +if("${Qt${PythonQt_QT_VERSION}_VERSION}" VERSION_GREATER_EQUAL "6.10.0") + list(APPEND qt_required_components CorePrivate) +endif() list(REMOVE_DUPLICATES qt_required_components) message(STATUS "${PROJECT_NAME}: Required Qt components [${qt_required_components}]") From a02b4c3fcfd559f710d66954edbece7ea44ed98c Mon Sep 17 00:00:00 2001 From: James Butler Date: Sun, 29 Mar 2026 13:45:38 -0400 Subject: [PATCH 29/30] CI: Add workflow for CMake build system\ --- .github/workflows/build_cmake.yml | 149 ++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 .github/workflows/build_cmake.yml diff --git a/.github/workflows/build_cmake.yml b/.github/workflows/build_cmake.yml new file mode 100644 index 000000000..cf7122835 --- /dev/null +++ b/.github/workflows/build_cmake.yml @@ -0,0 +1,149 @@ +name: Build (CMake) + +on: + push: + branches: + - main + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +defaults: + run: + shell: bash + +jobs: + build: + strategy: + fail-fast: false + matrix: + os: ['ubuntu', 'windows'] + # Qt 5.12.* is excluded: CMakeLists.txt requires Qt >= 5.15.0. + qt-version: [ '5.15.*', '6.10.*' ] + python-version: [ '3.12' ] + runs-on: ${{ matrix.os }}-latest + steps: + + - name: Install MSVC + if: ${{ matrix.os == 'windows' }} + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: amd64 + + - name: Install Qt ${{ matrix.qt-version }} + uses: jurplel/install-qt-action@v4 + with: + version: ${{ matrix.qt-version }} + modules: ${{ startsWith(matrix.qt-version, '6') && 'qt5compat qtscxml qtpositioning qtwebchannel qtmultimedia qtwebengine' || '' }} + arch: ${{ (matrix.os == 'ubuntu' && (startsWith(matrix.qt-version, '5') && 'gcc_64' || 'linux_gcc_64')) || startsWith(matrix.qt-version, '6') && 'win64_msvc2022_64' || 'win64_msvc2019_64' }} + + - name: Setup Python ${{ matrix.python-version }} + uses: actions/setup-python@v6 + with: + python-version: '${{ matrix.python-version }}' + + - name: Checkout PythonQt + uses: actions/checkout@v6 + + - name: Ccache + if: ${{ matrix.os == 'ubuntu' }} + uses: hendrikmuhs/ccache-action@v1.2.20 + with: + key: ${{ runner.os }}-cmake-${{ matrix.qt-version }} + evict-old-files: 'job' + + - name: Set environment + id: setenv + run: | + QT_VERSION_MAJOR=$(cut -f 1 -d . <<< "${{ matrix.qt-version }}") + echo "QT_VERSION_MAJOR=$QT_VERSION_MAJOR" >> $GITHUB_ENV + QT_VERSION_SHORT=$(cut -f 1,2 -d . <<< "${{ matrix.qt-version }}") + echo "QT_VERSION_SHORT=$QT_VERSION_SHORT" >> $GITHUB_OUTPUT + PYTHON_VERSION_FULL=$(python --version 2>&1 | cut -f 2 -d ' ') + PYTHON_VERSION_SHORT=$(cut -f 1,2 -d . <<< $PYTHON_VERSION_FULL) + echo "PYTHON_VERSION_SHORT=$PYTHON_VERSION_SHORT" >> $GITHUB_OUTPUT + echo "$pythonLocation/bin" >> $GITHUB_PATH + + - name: Build generator (Ubuntu) + if: ${{ matrix.os == 'ubuntu' }} + run: | + cmake -G Ninja -S generator -B generator/build \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_PREFIX_PATH="$QT_ROOT_DIR" \ + -DPythonQtGenerator_QT_VERSION=$QT_VERSION_MAJOR + cmake --build generator/build + + - name: Build generator (Windows) + if: ${{ matrix.os == 'windows' }} + shell: cmd + run: | + set QT_CMAKE_DIR=%QT_ROOT_DIR%\lib\cmake\Qt%QT_VERSION_MAJOR% + cmake -G "Visual Studio 17 2022" -S generator -B generator\build ^ + "-DCMAKE_PREFIX_PATH=%QT_ROOT_DIR%;%QT_ROOT_DIR%\lib\cmake" ^ + "-DQt%QT_VERSION_MAJOR%_DIR=%QT_CMAKE_DIR%" ^ + -DPythonQtGenerator_QT_VERSION=%QT_VERSION_MAJOR% || exit /b 1 + cmake --build generator\build --config Release || exit /b 1 + + - name: Generate Wrappers (Ubuntu) + if: ${{ matrix.os == 'ubuntu' }} + run: | + QTDIR="$QT_ROOT_DIR" \ + UBSAN_OPTIONS="halt_on_error=1" \ + ASAN_OPTIONS="detect_leaks=0:detect_stack_use_after_return=1:fast_unwind_on_malloc=0" \ + ./generator/build/PythonQtGenerator \ + --output-directory=. + + - name: Generate Wrappers (Windows) + if: ${{ matrix.os == 'windows' }} + shell: cmd + run: | + set QTDIR=%QT_ROOT_DIR% + generator\build\Release\PythonQtGenerator.exe --output-directory=. || exit /b 1 + + - name: Upload Wrappers + uses: actions/upload-artifact@v7 + with: + name: cmake_wrappers_${{ matrix.os }}_${{ steps.setenv.outputs.QT_VERSION_SHORT }} + path: generated_cpp + if-no-files-found: error + + - name: Build and test PythonQt (Ubuntu) + if: ${{ matrix.os == 'ubuntu' }} + run: | + cmake -G Ninja -S . -B build \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_PREFIX_PATH="$QT_ROOT_DIR" \ + -DPythonQt_QT_VERSION=$QT_VERSION_MAJOR \ + "-DPythonQt_GENERATED_PATH=$(pwd)/generated_cpp" \ + -DPythonQt_Wrap_QtCore=ON \ + -DBUILD_TESTING=ON \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ + "-DCMAKE_CXX_FLAGS=-fsanitize=address,undefined -fno-sanitize-recover=undefined" \ + "-DCMAKE_EXE_LINKER_FLAGS=-fsanitize=address,undefined" \ + "-DCMAKE_SHARED_LINKER_FLAGS=-fsanitize=address,undefined" + cmake --build build --parallel $(nproc) + PYTHONDEVMODE=1 PYTHONASYNCIODEBUG=1 PYTHONWARNINGS=error PYTHONMALLOC=malloc_debug \ + UBSAN_OPTIONS="halt_on_error=1" ASAN_OPTIONS="detect_leaks=0:detect_stack_use_after_return=1:fast_unwind_on_malloc=0" \ + QT_QPA_PLATFORM=offscreen \ + ctest --test-dir build --output-on-failure + + - name: Build and test PythonQt (Windows) + if: ${{ matrix.os == 'windows' }} + shell: cmd + run: | + set QT_CMAKE_DIR=%QT_ROOT_DIR%\lib\cmake\Qt%QT_VERSION_MAJOR% + cmake -G "Visual Studio 17 2022" -S . -B build ^ + "-DCMAKE_PREFIX_PATH=%QT_ROOT_DIR%;%QT_ROOT_DIR%\lib\cmake" ^ + "-DQt%QT_VERSION_MAJOR%_DIR=%QT_CMAKE_DIR%" ^ + -DPythonQt_QT_VERSION=%QT_VERSION_MAJOR% ^ + "-DPythonQt_GENERATED_PATH=%CD%\generated_cpp" ^ + -DPythonQt_Wrap_QtCore=ON ^ + -DBUILD_TESTING=ON || exit /b 1 + cmake --build build --config Release || exit /b 1 + set PYTHONDEVMODE=1 + set PYTHONASYNCIODEBUG=1 + set PYTHONWARNINGS=error + set QT_QPA_PLATFORM=offscreen + ctest --test-dir build --output-on-failure -C Release || exit /b 1 From 436435c9bbc095358b85585abbabf779fcba90a6 Mon Sep 17 00:00:00 2001 From: James Butler Date: Sun, 29 Mar 2026 16:26:48 -0400 Subject: [PATCH 30/30] CI: Remove undefined variable in qmake config --- .github/workflows/build_latest.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build_latest.yml b/.github/workflows/build_latest.yml index 214c3e6b9..21d1874f3 100644 --- a/.github/workflows/build_latest.yml +++ b/.github/workflows/build_latest.yml @@ -122,7 +122,6 @@ jobs: python --version qmake CONFIG+=release CONFIG-=debug_and_release CONFIG-=debug_and_release_target ^ CONFIG+=exclude_generator ^ - "PYTHONQTALL_CONFIG=${{ matrix.pythonqtall-config }}" ^ "PYTHON_PATH=%pythonLocation%" ^ "PYTHON_VERSION=${{ steps.setenv.outputs.PYTHON_VERSION_SHORT }}" ^ PythonQt.pro