From f2c1b2992129c58c7323bfd8a9c8ffdf9a4290fe Mon Sep 17 00:00:00 2001 From: Eric Heim Date: Wed, 6 May 2015 17:27:13 +0200 Subject: [PATCH 01/28] Added CMake build system. --- CMakeLists.txt | 536 +++++++++++++++++++++++++++---------------------- 1 file changed, 299 insertions(+), 237 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d3e378a..ba904bec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,26 +1,42 @@ -#----------------------------------------------------------------------------- -# 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 2.8) - -#----------------------------------------------------------------------------- -project(PythonQt) -#----------------------------------------------------------------------------- - -#----------------------------------------------------------------------------- -# Python libraries - -find_package(PythonLibs REQUIRED) -include_directories("${PYTHON_INCLUDE_DIR}") -add_definitions(-DPYTHONQT_USE_RELEASE_PYTHON_FALLBACK) - -#----------------------------------------------------------------------------- -# Build options - +#----------------------------------------------------------------------------- +# 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 2.8) + +#----------------------------------------------------------------------------- +project(PythonQt) +#----------------------------------------------------------------------------- + +include(CTestUseLaunchers OPTIONAL) + +#---------------------------------------------------------------------------- +# Qt version + +set(DESIRED_QT_VERSION 5 CACHE STRING "Pick a version of Qt to use: 4 or 5") + +set(minimum_required_qt5_version "5.3.0") +set(minimum_required_qt4_version "4.6.2") + +#----------------------------------------------------------------------------- +# Python libraries + +find_package(PythonLibs REQUIRED) +include_directories("${PYTHON_INCLUDE_DIR}") +add_definitions(-DPYTHONQT_USE_RELEASE_PYTHON_FALLBACK) + +#----------------------------------------------------------------------------- +# Build options +option(PythonQt_Wrap_QtAll "Make all Qt components available in python" OFF) + +if(DESIRED_QT_VERSION MATCHES 4) + set(qtlibs core gui network opengl sql svg uitools webkit xml xmlpatterns locale) +else() + set(qtlibs Core Network OpenGL Sql Svg Widgets WebKitWidgets Xml XmlPatterns UiTools) +endif() if(NOT DEFINED PythonQt_INSTALL_RUNTIME_DIR) set(PythonQt_INSTALL_RUNTIME_DIR bin) endif() @@ -37,220 +53,266 @@ if(NOT DEFINED PythonQt_INSTALL_INCLUDE_DIR) set(PythonQt_INSTALL_INCLUDE_DIR include/PythonQt) endif() -option(PythonQt_Wrap_QtAll "Make all Qt components available in python" OFF) - -set(qtlibs core gui network opengl sql svg uitools webkit xml xmlpatterns) -foreach(qtlib ${qtlibs}) - OPTION(PythonQt_Wrap_Qt${qtlib} "Make all of Qt${qtlib} available in python" OFF) -endforeach() - -# Force option if it applies -if(PythonQt_Wrap_QtAll) - list(REMOVE_ITEM qtlibs xmlpatterns) # xmlpatterns wrapper does *NOT* build at all :( - foreach(qtlib ${qtlibs}) - if(NOT ${PythonQt_Wrap_Qt${qtlib}}) - set(PythonQt_Wrap_Qt${qtlib} ON CACHE BOOL "Make all of Qt${qtlib} available in python" FORCE) - message(STATUS "Enabling [PythonQt_Wrap_Qt${qtlib}] 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 - -set(minimum_required_qt_version "4.6.2") - -find_package(Qt4) - -if(QT4_FOUND) - - set(found_qt_version ${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}.${QT_VERSION_PATCH}) - - 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() - - # Enable required qt module - foreach(qtlib network opengl sql svg uitools webkit xml xmlpatterns) - string(TOUPPER ${qtlib} qtlib_uppercase) - if (NOT ${QT_QT${qtlib_uppercase}_FOUND}) - message(FATAL_ERROR "QT_QT${qtlib_uppercase} *not* FOUND - Try to disable PythonQt_Wrap_Qt${qtlib}") - endif() - set(QT_USE_QT${qtlib_uppercase} ${PythonQt_Wrap_Qt${qtlib}}) - endforeach() - - set(QT_USE_QTTEST ${BUILD_TESTING}) - - 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() - -#----------------------------------------------------------------------------- -# The variable "generated_cpp_suffix" allows to conditionnally compile the generated wrappers -# associated with the Qt version being used. -set(generated_cpp_suffix "_${QT_VERSION_MAJOR}${QT_VERSION_MINOR}") -if("${generated_cpp_suffix}" STREQUAL "_46") - set(generated_cpp_suffix "_47") # Also use 4.7 wrappers for 4.6.x version -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/PythonQtQFileImporter.cpp - src/PythonQtSignalReceiver.cpp - src/PythonQtSlot.cpp - src/PythonQtSignal.cpp - src/PythonQtStdDecorators.cpp - src/PythonQtStdIn.cpp - src/PythonQtStdOut.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/PythonQtQFileImporter.h - src/PythonQtSignalReceiver.h - src/PythonQtSlot.h - src/PythonQtSignal.h - src/PythonQtStdDecorators.h - src/PythonQtStdIn.h - src/PythonQtStdOut.h - src/PythonQtSystem.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 core gui network opengl sql svg uitools webkit xml xmlpatterns) - - if (${PythonQt_Wrap_Qt${qtlib}}) - - ADD_DEFINITIONS(-DPYTHONQT_WRAP_Qt${qtlib}) - - set(file_prefix generated_cpp${generated_cpp_suffix}/com_trolltech_qt_${qtlib}/com_trolltech_qt_${qtlib}) - - foreach(index RANGE 0 11) - - # 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() - -#----------------------------------------------------------------------------- -# UI files -set(ui_sources ) - -#----------------------------------------------------------------------------- -# Resources -set(qrc_sources ) - -#----------------------------------------------------------------------------- -# 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}) - -#----------------------------------------------------------------------------- -# Build the library - -include_directories( - ${CMAKE_CURRENT_SOURCE_DIR}/src - ) - -add_library(PythonQt SHARED - ${sources} - ${gen_moc_sources} - ${gen_ui_sources} - ${gen_qrc_sources} - ) -set_target_properties(PythonQt PROPERTIES DEFINE_SYMBOL PYTHONQT_EXPORTS) - -# -# That should solve linkage error on Mac when the project is used in a superbuild setup -# See http://blog.onesadcookie.com/2008/01/installname-magic.html -# -set_target_properties(PythonQt PROPERTIES - INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib" - ) - -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 +option(PythonQt_Wrap_QtAll "Make all Qt components available in python" OFF) + +set(qtlibs core gui network opengl sql svg uitools webkit xml xmlpatterns) +foreach(qtlib ${qtlibs}) + OPTION(PythonQt_Wrap_Qt${qtlib} "Make all of Qt${qtlib} available in python" OFF) +endforeach() + +# Force option if it applies +if(PythonQt_Wrap_QtAll) + list(REMOVE_ITEM qtlibs XmlPatterns) # xmlpatterns wrapper does *NOT* build at all :( + foreach(qtlib ${qtlibs}) + if(NOT ${PythonQt_Wrap_Qt${qtlib}}) + set(PythonQt_Wrap_Qt${qtlib} ON CACHE BOOL "Make all of Qt${qtlib} available in python" FORCE) + message(STATUS "Enabling [PythonQt_Wrap_Qt${qtlib}] 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 + +if(DESIRED_QT_VERSION MATCHES 5) + find_package(Qt5 ${minimum_required_qt5_version} COMPONENTS ${qtlibs} REQUIRED) + + if(Qt5_DIR) + get_filename_component(_Qt5_DIR "${Qt5_DIR}/../../../" ABSOLUTE) + list(FIND CMAKE_PREFIX_PATH "${_Qt5_DIR}" _result) + if(_result LESS 0) + set(CMAKE_PREFIX_PATH "${_Qt5_DIR};${CMAKE_PREFIX_PATH}" CACHE PATH "" FORCE) + endif() + endif() + + get_target_property(_qmake_exec Qt5::qmake LOCATION) + execute_process(COMMAND ${_qmake_exec} -query QT_INSTALL_BINS + RESULT_VARIABLE _result + OUTPUT_VARIABLE QT_BINARY_DIR + ERROR_VARIABLE _error + ) + string(STRIP "${QT_BINARY_DIR}" QT_BINARY_DIR) + if(_result OR NOT EXISTS "${QT_BINARY_DIR}") + message(FATAL_ERROR "Could not determine Qt binary directory: ${_result} ${QT_BINARY_DIR} ${_error}") + endif() + + #----------------------------------------------------------------------------- + # The variable "generated_cpp_suffix" allows to conditionnally compile the generated wrappers + # associated with the Qt version being used. + set(generated_cpp_suffix "_${Qt5Core_VERSION_MAJOR}${Qt5Core_VERSION_MINOR}") + +else() + #----------------------------------------------------------------------------- + # Setup Qt4 + + find_package(Qt4) + + if(QT4_FOUND) + + set(found_qt_version ${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}.${QT_VERSION_PATCH}) + + if(${found_qt_version} VERSION_LESS ${minimum_required_qt4_version}) + message(FATAL_ERROR "error: PythonQt requires Qt >= ${minimum_required_qt4_version} -- you cannot use Qt ${found_qt_version}.") + endif() + + # Enable required qt module + foreach(qtlib network opengl sql svg uitools webkit xml xmlpatterns) + string(TOUPPER ${qtlib} qtlib_uppercase) + if (NOT ${QT_QT${qtlib_uppercase}_FOUND}) + message(FATAL_ERROR "QT_QT${${qtlib_uppercase} *not* FOUND - Try to disable PythonQt_Wrap_Qt${qtlib}") + endif() + set(QT_USE_QT${qtlib_uppercase} ${PythonQt_Wrap_Qt${qtlib}}) + endforeach() + + 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() + + #----------------------------------------------------------------------------- + # The variable "generated_cpp_suffix" allows to conditionnally compile the generated wrappers + # associated with the Qt version being used. + set(generated_cpp_suffix "_${QT_VERSION_MAJOR}${QT_VERSION_MINOR}") + + # TODO: generated headers for Qt4.8 contains several strange locales that are not available out of the box + # force 4.7 + if("${generated_cpp_suffix}" STREQUAL "_46" OR "${generated_cpp_suffix}" STREQUAL "_48") + set(generated_cpp_suffix "_47") # Also use 4.7 wrappers for 4.6.x version + endif() +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/PythonQtQFileImporter.cpp + src/PythonQtSignalReceiver.cpp + src/PythonQtSlot.cpp + src/PythonQtSignal.cpp + src/PythonQtStdDecorators.cpp + src/PythonQtStdIn.cpp + src/PythonQtStdOut.cpp + src/gui/PythonQtScriptingConsole.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/PythonQtQFileImporter.h + src/PythonQtSignalReceiver.h + src/PythonQtSlot.h + src/PythonQtSignal.h + src/PythonQtStdDecorators.h + src/PythonQtStdIn.h + src/PythonQtStdOut.h + src/PythonQtSystem.h + src/PythonQtVariants.h + src/PythonQtPythonInclude.h + src/PythonQtUtils.h +) +if(DESIRED_QT_VERSION MATCHES 4) + set(sources ${sources} generated_cpp${generated_cpp_suffix}/PythonQt_QtBindings.cpp) + set(headers ${headers} generated_cpp${generated_cpp_suffix}/PythonQt_QtBindings.h) +endif() +#----------------------------------------------------------------------------- +# 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 core gui network opengl sql svg uitools webkit xml xmlpatterns) + + if (${PythonQt_Wrap_Qt${qtlib}}) + + ADD_DEFINITIONS(-DPYTHONQT_WRAP_Qt${qtlib}) + + set(file_prefix generated_cpp${generated_cpp_suffix}/com_trolltech_qt_${qtlib}/com_trolltech_qt_${qtlib}) + + foreach(index RANGE 0 11) + + # 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() + +#----------------------------------------------------------------------------- +# UI files +set(ui_sources ) + +#----------------------------------------------------------------------------- +# Resources +set(qrc_sources ) + +#----------------------------------------------------------------------------- +# Do wrapping +if(DESIRED_QT_VERSION MATCHES 4) + qt4_wrap_cpp(gen_moc_sources ${moc_sources}) + qt4_wrap_ui(gen_ui_sources ${ui_sources}) + qt4_add_resources(gen_qrc_sources ${qrc_sources}) +else() + qt5_wrap_cpp(gen_moc_sources ${moc_sources}) + qt5_wrap_ui(gen_ui_sources ${ui_sources}) + qt5_add_resources(gen_qrc_sources ${qrc_sources}) + + include_directories(${Qt5Core_INCLUDE_DIRS}) + include_directories(${Qt5Widgets_INCLUDE_DIRS}) + include_directories(${Network_INCLUDE_DIRS}) + include_directories(${OpenGL_INCLUDE_DIRS}) + include_directories(${Sql_INCLUDE_DIRS}) + include_directories(${Svg_INCLUDE_DIRS}) + include_directories(${WebKitWidgets_INCLUDE_DIRS}) + include_directories(${Xml_INCLUDE_DIRS}) + include_directories(${XmlPatterns_INCLUDE_DIRS}) + include_directories(${UiTools_INCLUDE_DIRS}) +endif() +#----------------------------------------------------------------------------- +# Build the library + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/src + ) + +add_library(PythonQt SHARED + ${sources} + ${gen_moc_sources} + ${gen_ui_sources} + ${gen_qrc_sources} + ) +set_target_properties(PythonQt PROPERTIES DEFINE_SYMBOL PYTHONQT_EXPORTS) + +# +# That should solve linkage error on Mac when the project is used in a superbuild setup +# See http://blog.onesadcookie.com/2008/01/installname-magic.html +# +set_target_properties(PythonQt PROPERTIES + INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib" + ) + +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}) From bd4e1e5b777eda397896ad240f0bdce3d1e0297f Mon Sep 17 00:00:00 2001 From: Eric Heim Date: Mon, 11 May 2015 14:11:17 +0200 Subject: [PATCH 02/28] Added qt5 in testing and variable re-naming to match the previously used naming convetions --- CMakeLists.txt | 124 ++++++++++++++++++++++++++----------------------- 1 file changed, 65 insertions(+), 59 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ba904bec..1e40d589 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ include(CTestUseLaunchers OPTIONAL) #---------------------------------------------------------------------------- # Qt version -set(DESIRED_QT_VERSION 5 CACHE STRING "Pick a version of Qt to use: 4 or 5") +set(PythonQt_QT_VERSION 5 CACHE STRING "Pick a version of Qt to use: 4 or 5") set(minimum_required_qt5_version "5.3.0") set(minimum_required_qt4_version "4.6.2") @@ -32,27 +32,28 @@ add_definitions(-DPYTHONQT_USE_RELEASE_PYTHON_FALLBACK) # Build options option(PythonQt_Wrap_QtAll "Make all Qt components available in python" OFF) -if(DESIRED_QT_VERSION MATCHES 4) +if(PythonQt_QT_VERSION MATCHES 4) set(qtlibs core gui network opengl sql svg uitools webkit xml xmlpatterns locale) else() set(qtlibs Core Network OpenGL Sql Svg Widgets WebKitWidgets Xml XmlPatterns UiTools) endif() -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() - + +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() + option(PythonQt_Wrap_QtAll "Make all Qt components available in python" OFF) set(qtlibs core gui network opengl sql svg uitools webkit xml xmlpatterns) @@ -81,7 +82,7 @@ endif() #----------------------------------------------------------------------------- # Setup Qt -if(DESIRED_QT_VERSION MATCHES 5) +if(PythonQt_QT_VERSION MATCHES 5) find_package(Qt5 ${minimum_required_qt5_version} COMPONENTS ${qtlibs} REQUIRED) if(Qt5_DIR) @@ -141,8 +142,8 @@ else() # associated with the Qt version being used. set(generated_cpp_suffix "_${QT_VERSION_MAJOR}${QT_VERSION_MINOR}") - # TODO: generated headers for Qt4.8 contains several strange locales that are not available out of the box - # force 4.7 + # TODO: generated headers for Qt4.8 contains several locales that are not available + # out of the box -> force 4.7 if("${generated_cpp_suffix}" STREQUAL "_46" OR "${generated_cpp_suffix}" STREQUAL "_48") set(generated_cpp_suffix "_47") # Also use 4.7 wrappers for 4.6.x version endif() @@ -205,7 +206,7 @@ set(headers src/PythonQtPythonInclude.h src/PythonQtUtils.h ) -if(DESIRED_QT_VERSION MATCHES 4) +if(PythonQt_QT_VERSION MATCHES 4) set(sources ${sources} generated_cpp${generated_cpp_suffix}/PythonQt_QtBindings.cpp) set(headers ${headers} generated_cpp${generated_cpp_suffix}/PythonQt_QtBindings.h) endif() @@ -261,7 +262,7 @@ set(qrc_sources ) #----------------------------------------------------------------------------- # Do wrapping -if(DESIRED_QT_VERSION MATCHES 4) +if(PythonQt_QT_VERSION MATCHES 4) qt4_wrap_cpp(gen_moc_sources ${moc_sources}) qt4_wrap_ui(gen_ui_sources ${ui_sources}) qt4_add_resources(gen_qrc_sources ${qrc_sources}) @@ -313,39 +314,44 @@ target_link_libraries(PythonQt # 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 - ) - - list(APPEND test_sources - tests/PythonQtTests.cpp - tests/PythonQtTests.h - ) - - QT4_WRAP_CPP(test_sources - tests/PythonQtTests.h - ) - - set_property(SOURCE tests/PythonQtTestMain.cpp PROPERTY COMPILE_DEFINITIONS "main=tests_PythonQtTestMain") - - add_executable(PythonQtCppTests ${test_sources}) - target_link_libraries(PythonQtCppTests PythonQt) - - add_test( - NAME tests_PythonQtTestMain - COMMAND ${Slicer_LAUNCH_COMMAND} $ tests/PythonQtTestMain - ) -endif() - + 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 + ) + + list(APPEND test_sources + tests/PythonQtTests.cpp + tests/PythonQtTests.h + ) + if(PythonQt_QT_VERSION MATCHES 4) + QT4_WRAP_CPP(test_sources + tests/PythonQtTests.h + ) + else() + QT5_WRAP_CPP(test_sources + tests/PythonQtTests.h + ) + endif() + + set_property(SOURCE tests/PythonQtTestMain.cpp PROPERTY COMPILE_DEFINITIONS "main=tests_PythonQtTestMain") + + add_executable(PythonQtCppTests ${test_sources}) + target_link_libraries(PythonQtCppTests PythonQt) + + add_test( + NAME tests_PythonQtTestMain + COMMAND ${Slicer_LAUNCH_COMMAND} $ tests/PythonQtTestMain + ) +endif() + From 0fca79f8cd2e9fada9affbec2d8e40691ba20417 Mon Sep 17 00:00:00 2001 From: Eric Heim Date: Mon, 11 May 2015 17:28:59 +0200 Subject: [PATCH 03/28] fixed rebase merge conflicts --- CMakeLists.txt | 51 +++++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e40d589..842c86cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,7 +56,6 @@ endif() option(PythonQt_Wrap_QtAll "Make all Qt components available in python" OFF) -set(qtlibs core gui network opengl sql svg uitools webkit xml xmlpatterns) foreach(qtlib ${qtlibs}) OPTION(PythonQt_Wrap_Qt${qtlib} "Make all of Qt${qtlib} available in python" OFF) endforeach() @@ -83,6 +82,11 @@ endif() # Setup Qt if(PythonQt_QT_VERSION MATCHES 5) + + if(BUILD_TESTING) + list(APPEND qtlibs Test) + endif() + find_package(Qt5 ${minimum_required_qt5_version} COMPONENTS ${qtlibs} REQUIRED) if(Qt5_DIR) @@ -104,6 +108,11 @@ if(PythonQt_QT_VERSION MATCHES 5) message(FATAL_ERROR "Could not determine Qt binary directory: ${_result} ${QT_BINARY_DIR} ${_error}") endif() + foreach(qtlib ${qtlibs}) + include_directories(${Qt5${qtlib}_INCLUDE_DIRS}) + add_definitions(${Qt5${qtlib}_DEFINITIONS}) + endforeach() + #----------------------------------------------------------------------------- # The variable "generated_cpp_suffix" allows to conditionnally compile the generated wrappers # associated with the Qt version being used. @@ -124,7 +133,7 @@ else() endif() # Enable required qt module - foreach(qtlib network opengl sql svg uitools webkit xml xmlpatterns) + foreach(qtlib ${qtlibs}) string(TOUPPER ${qtlib} qtlib_uppercase) if (NOT ${QT_QT${qtlib_uppercase}_FOUND}) message(FATAL_ERROR "QT_QT${${qtlib_uppercase} *not* FOUND - Try to disable PythonQt_Wrap_Qt${qtlib}") @@ -137,12 +146,15 @@ else() message(FATAL_ERROR "error: Qt4 was not found on your system. You probably need to set the QT_QMAKE_EXECUTABLE variable") endif() + # Enable QtTest in Qt4 is the option BUILD_TESTING was activated + set(QT_USE_QTTEST ${BUILD_TESTING}) + #----------------------------------------------------------------------------- # The variable "generated_cpp_suffix" allows to conditionnally compile the generated wrappers # associated with the Qt version being used. set(generated_cpp_suffix "_${QT_VERSION_MAJOR}${QT_VERSION_MINOR}") - # TODO: generated headers for Qt4.8 contains several locales that are not available + # TODO: generated headers for Qt4.8 contains several locales that are not available # out of the box -> force 4.7 if("${generated_cpp_suffix}" STREQUAL "_46" OR "${generated_cpp_suffix}" STREQUAL "_48") set(generated_cpp_suffix "_47") # Also use 4.7 wrappers for 4.6.x version @@ -225,28 +237,28 @@ set(moc_sources #----------------------------------------------------------------------------- # Add extra sources -foreach(qtlib core gui network opengl sql svg uitools webkit xml xmlpatterns) - +foreach(qtlib ${qtlibs}) + if (${PythonQt_Wrap_Qt${qtlib}}) - + ADD_DEFINITIONS(-DPYTHONQT_WRAP_Qt${qtlib}) - + set(file_prefix generated_cpp${generated_cpp_suffix}/com_trolltech_qt_${qtlib}/com_trolltech_qt_${qtlib}) - + foreach(index RANGE 0 11) - + # 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() @@ -270,17 +282,6 @@ else() qt5_wrap_cpp(gen_moc_sources ${moc_sources}) qt5_wrap_ui(gen_ui_sources ${ui_sources}) qt5_add_resources(gen_qrc_sources ${qrc_sources}) - - include_directories(${Qt5Core_INCLUDE_DIRS}) - include_directories(${Qt5Widgets_INCLUDE_DIRS}) - include_directories(${Network_INCLUDE_DIRS}) - include_directories(${OpenGL_INCLUDE_DIRS}) - include_directories(${Sql_INCLUDE_DIRS}) - include_directories(${Svg_INCLUDE_DIRS}) - include_directories(${WebKitWidgets_INCLUDE_DIRS}) - include_directories(${Xml_INCLUDE_DIRS}) - include_directories(${XmlPatterns_INCLUDE_DIRS}) - include_directories(${UiTools_INCLUDE_DIRS}) endif() #----------------------------------------------------------------------------- # Build the library @@ -288,7 +289,7 @@ endif() include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/src ) - + add_library(PythonQt SHARED ${sources} ${gen_moc_sources} @@ -342,7 +343,7 @@ if(BUILD_TESTING) QT5_WRAP_CPP(test_sources tests/PythonQtTests.h ) - endif() + endif() set_property(SOURCE tests/PythonQtTestMain.cpp PROPERTY COMPILE_DEFINITIONS "main=tests_PythonQtTestMain") From 1cb4c4f9e97726b97d01166dc43f03e316e792dc Mon Sep 17 00:00:00 2001 From: Eric Heim Date: Tue, 12 May 2015 09:57:34 +0200 Subject: [PATCH 04/28] fixed win32 linker issues and test build with qt5 --- CMakeLists.txt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 842c86cc..9687a71e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -108,8 +108,10 @@ if(PythonQt_QT_VERSION MATCHES 5) message(FATAL_ERROR "Could not determine Qt binary directory: ${_result} ${QT_BINARY_DIR} ${_error}") endif() + set(QT_LIBRARIES ) foreach(qtlib ${qtlibs}) include_directories(${Qt5${qtlib}_INCLUDE_DIRS}) + list(APPEND QT_LIBRARIES ${Qt5${qtlib}_LIBRARIES}) add_definitions(${Qt5${qtlib}_DEFINITIONS}) endforeach() @@ -141,14 +143,13 @@ else() set(QT_USE_QT${qtlib_uppercase} ${PythonQt_Wrap_Qt${qtlib}}) endforeach() + set(QT_USE_QTTEST ${BUILD_TESTING}) + 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() - # Enable QtTest in Qt4 is the option BUILD_TESTING was activated - set(QT_USE_QTTEST ${BUILD_TESTING}) - #----------------------------------------------------------------------------- # The variable "generated_cpp_suffix" allows to conditionnally compile the generated wrappers # associated with the Qt version being used. @@ -310,7 +311,7 @@ target_link_libraries(PythonQt ${PYTHON_LIBRARY} ${QT_LIBRARIES} ) - +message(${QT_LIBRARIES}) #----------------------------------------------------------------------------- # Install library (on windows, put the dll in 'bin' and the archive in 'lib') @@ -348,7 +349,7 @@ if(BUILD_TESTING) set_property(SOURCE tests/PythonQtTestMain.cpp PROPERTY COMPILE_DEFINITIONS "main=tests_PythonQtTestMain") add_executable(PythonQtCppTests ${test_sources}) - target_link_libraries(PythonQtCppTests PythonQt) + target_link_libraries(PythonQtCppTests PythonQt ${Qt5Test_LIBRARIES}) add_test( NAME tests_PythonQtTestMain From 36ab9c7c9efdbf2010aacf9b6abf0d1cc7df670a Mon Sep 17 00:00:00 2001 From: Eric Heim Date: Tue, 12 May 2015 10:04:47 +0200 Subject: [PATCH 05/28] removed debug message --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9687a71e..b31e2430 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -311,7 +311,7 @@ target_link_libraries(PythonQt ${PYTHON_LIBRARY} ${QT_LIBRARIES} ) -message(${QT_LIBRARIES}) + #----------------------------------------------------------------------------- # Install library (on windows, put the dll in 'bin' and the archive in 'lib') From e31864b362d6ab75f3379ead17510dcaa91c40b9 Mon Sep 17 00:00:00 2001 From: Eric Heim Date: Wed, 10 Feb 2016 15:59:49 +0100 Subject: [PATCH 06/28] Added Qt versions greater than 5.4 in cmake build. Use 5.4 wrappers as default like it's done in the qt based build system --- CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index b31e2430..668af80b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -120,6 +120,12 @@ if(PythonQt_QT_VERSION MATCHES 5) # associated with the Qt version being used. set(generated_cpp_suffix "_${Qt5Core_VERSION_MAJOR}${Qt5Core_VERSION_MINOR}") + # Use Qt5.4 as default for higher versions like it's done in build/common.prf + if(${Qt5Core_VERSION_MINOR} GREATER 4) + set(generated_cpp_suffix "_${Qt5Core_VERSION_MAJOR}4") + endif() + + else() #----------------------------------------------------------------------------- # Setup Qt4 From 3388c4f2a6dc2a213f9ddc3bde7b64135944d583 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Mon, 31 Aug 2015 11:28:32 -0400 Subject: [PATCH 07/28] Update README.md to describe the "patched-5" branch --- README.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9e43ea73..841026d3 100644 --- a/README.md +++ b/README.md @@ -43,8 +43,17 @@ Additional configure options are: Available branches ------------------ -This repository contains three branches: -* Based on [r245](http://sourceforge.net/p/pythonqt/code/245/) +This repository contains 5 branches: + +### patched-5 +* Based on patched-4 + [r395](http://sourceforge.net/p/pythonqt/code/395/) +* List of features: + * CMake: + * Fix install rules + * Fix "_invalid_parameter_noinfo_noreturn" link error + * PythonQt: + * Add Qt5 support + * Add PY3K support ### patched-4 * Based on patched-3 + [r245](http://sourceforge.net/p/pythonqt/code/245/) From 9ce3be392c0a84a50c59bd1dc5c9abe2723abc12 Mon Sep 17 00:00:00 2001 From: Max Smolens Date: Fri, 28 Aug 2015 14:16:08 -0400 Subject: [PATCH 08/28] Add missing refcount decrements when creating wrappers PyObject_GetAttrString returns a new reference. PyDict_SetItemString does not steal a reference, so Py_DECREF should be called after PyDict_SetItemString. --- src/PythonQt.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/PythonQt.cpp b/src/PythonQt.cpp index 1b4954f3..92ff9456 100644 --- a/src/PythonQt.cpp +++ b/src/PythonQt.cpp @@ -670,6 +670,7 @@ PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtCla // create the new type object by calling the type result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, NULL); + Py_DECREF(moduleName); Py_DECREF(baseClasses); Py_DECREF(typeDict); Py_DECREF(args); @@ -703,6 +704,7 @@ PyObject* PythonQtPrivate::createNewPythonQtEnumWrapper(const char* enumName, Py // create the new int derived type object by calling the core type result = PyObject_Call((PyObject *)&PyType_Type, args, NULL); + Py_DECREF(module); Py_DECREF(baseClasses); Py_DECREF(typeDict); Py_DECREF(args); From a7e2b88c4c42390fedc31306a17a062552e61331 Mon Sep 17 00:00:00 2001 From: Max Smolens Date: Mon, 31 Aug 2015 13:46:21 -0400 Subject: [PATCH 09/28] Fix refcount of PyInt_Type when creating enum wrapper This commit increments the refcount of the built-in PyInt_Type instance when creating an enum wrapper. This is necessary because PyTuple_SET_ITEM steals a reference to that instance. Fixing the refcount prevents a crash when calling Py_Finalize(). --- src/PythonQt.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PythonQt.cpp b/src/PythonQt.cpp index 92ff9456..2ee76cfb 100644 --- a/src/PythonQt.cpp +++ b/src/PythonQt.cpp @@ -693,6 +693,7 @@ PyObject* PythonQtPrivate::createNewPythonQtEnumWrapper(const char* enumName, Py PyObject* className = PyString_FromString(enumName); PyObject* baseClasses = PyTuple_New(1); + Py_INCREF(&PyInt_Type); PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PyInt_Type); PyObject* module = PyObject_GetAttrString(parentObject, "__module__"); From 296b9027539bd658c62c2eb15df63d7621ad7662 Mon Sep 17 00:00:00 2001 From: Max Smolens Date: Fri, 28 Aug 2015 14:14:58 -0400 Subject: [PATCH 10/28] Prevent crash when an object is destroyed after calling PythonQt::cleanup() In certain situations the dealloc callback PythonQtInstanceWrapper_dealloc is called after PythonQt::cleanup() has been run. This can happen when Python destroys objects during Py_Finalize(). This commit adds a check that PythonQt is still initialized in the dealloc callback. --- src/PythonQtInstanceWrapper.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/PythonQtInstanceWrapper.cpp b/src/PythonQtInstanceWrapper.cpp index ea4de976..41a39591 100644 --- a/src/PythonQtInstanceWrapper.cpp +++ b/src/PythonQtInstanceWrapper.cpp @@ -118,7 +118,9 @@ static void PythonQtInstanceWrapper_deleteObject(PythonQtInstanceWrapper* self, static void PythonQtInstanceWrapper_dealloc(PythonQtInstanceWrapper* self) { - PythonQtInstanceWrapper_deleteObject(self); + if (PythonQt::self()) { + PythonQtInstanceWrapper_deleteObject(self); + } self->_obj.~QPointer(); Py_TYPE(self)->tp_free((PyObject*)self); } From f89195423a4e59009c792d2c455c1da604eccc98 Mon Sep 17 00:00:00 2001 From: florianlink Date: Fri, 29 May 2015 09:01:41 +0000 Subject: [PATCH 11/28] fixed error handling for evalFile made name->objectName alias optional (off by default, add PYTHONQT_SUPPORT_NAME_PROPERTY to DEFINES if you need it) added py_delete() slot support for built-in delete() method git-svn-id: http://svn.code.sf.net/p/pythonqt/code/trunk@396 ea8d5007-eb21-0410-b261-ccb3ea6e24a9 --- src/PythonQt.cpp | 4 +--- src/PythonQtClassInfo.cpp | 2 ++ src/PythonQtInstanceWrapper.cpp | 9 ++++++++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/PythonQt.cpp b/src/PythonQt.cpp index 2ee76cfb..7ba6ab55 100644 --- a/src/PythonQt.cpp +++ b/src/PythonQt.cpp @@ -880,12 +880,10 @@ QVariant PythonQt::evalScript(PyObject* object, const QString& script, int start void PythonQt::evalFile(PyObject* module, const QString& filename) { + // NOTE: error checking is done by parseFile and evalCode PythonQtObjectPtr code = parseFile(filename); - clearError(); if (code) { evalCode(module, code); - } else { - handleError(); } } diff --git a/src/PythonQtClassInfo.cpp b/src/PythonQtClassInfo.cpp index 4a69e25d..79ba3e8f 100644 --- a/src/PythonQtClassInfo.cpp +++ b/src/PythonQtClassInfo.cpp @@ -134,6 +134,7 @@ bool PythonQtClassInfo::lookForPropertyAndCache(const char* memberName) const char* attributeName = memberName; // look for properties int i = _meta->indexOfProperty(attributeName); +#ifdef PYTHONQT_SUPPORT_NAME_PROPERTY if (i==-1) { // try to map name to objectName if (qstrcmp(attributeName, "name")==0) { @@ -142,6 +143,7 @@ bool PythonQtClassInfo::lookForPropertyAndCache(const char* memberName) i = _meta->indexOfProperty(attributeName); } } +#endif if (i!=-1) { PythonQtMemberInfo newInfo(_meta->property(i)); _cachedMembers.insert(attributeName, newInfo); diff --git a/src/PythonQtInstanceWrapper.cpp b/src/PythonQtInstanceWrapper.cpp index 41a39591..86ff8a6f 100644 --- a/src/PythonQtInstanceWrapper.cpp +++ b/src/PythonQtInstanceWrapper.cpp @@ -345,7 +345,14 @@ static PyObject *PythonQtInstanceWrapper_help(PythonQtInstanceWrapper* obj) PyObject *PythonQtInstanceWrapper_delete(PythonQtInstanceWrapper * self) { - PythonQtInstanceWrapper_deleteObject(self, true); + PythonQtMemberInfo deleteSlot = self->classInfo()->member("py_delete"); + if (deleteSlot._type == PythonQtMemberInfo::Slot) { + // call the py_delete slot instead of internal C++ destructor... + PyObject* resultObj = PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, deleteSlot._slot, NULL, NULL, self->_wrappedPtr); + Py_XDECREF(resultObj); + } else { + PythonQtInstanceWrapper_deleteObject(self, true); + } Py_INCREF(Py_None); return Py_None; } From aea3b945cff4bd5d2911605e2087a59b6cee12a2 Mon Sep 17 00:00:00 2001 From: florianlink Date: Wed, 3 Jun 2015 09:42:12 +0000 Subject: [PATCH 12/28] fixed a missign QMetaObject::disconnect which leads to connection leaking added removeSignalHandlers() git-svn-id: http://svn.code.sf.net/p/pythonqt/code/trunk@398 ea8d5007-eb21-0410-b261-ccb3ea6e24a9 --- src/PythonQt.cpp | 12 ++++++++++++ src/PythonQt.h | 3 +++ src/PythonQtSignalReceiver.cpp | 2 ++ 3 files changed, 17 insertions(+) diff --git a/src/PythonQt.cpp b/src/PythonQt.cpp index 7ba6ab55..9cbcfba3 100644 --- a/src/PythonQt.cpp +++ b/src/PythonQt.cpp @@ -1389,6 +1389,18 @@ void PythonQtPrivate::removeSignalEmitter(QObject* obj) _signalReceivers.remove(obj); } +void PythonQt::removeSignalHandlers() +{ + QList signalReceivers = _p->_signalReceivers.values(); + + // just delete all signal receivers, they will remove themselves via removeSignalEmitter() + foreach(PythonQtSignalReceiver* receiver, signalReceivers) { + delete receiver; + } + // just to be sure, clear the receiver map as well + _p->_signalReceivers.clear(); +} + namespace { //! adapted from python source file "pythonrun.c", function "handle_system_exit" diff --git a/src/PythonQt.h b/src/PythonQt.h index fe74371c..01ef8206 100644 --- a/src/PythonQt.h +++ b/src/PythonQt.h @@ -365,6 +365,9 @@ class PYTHONQT_EXPORT PythonQt : public QObject { //! remove a signal handler from the given \c signal of \c obj bool removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver); + //! globally removes all signal handlers (connections between QObjects and Python). + void removeSignalHandlers(); + //@} //--------------------------------------------------------------------------- diff --git a/src/PythonQtSignalReceiver.cpp b/src/PythonQtSignalReceiver.cpp index 0d8ac6ea..d81ab176 100644 --- a/src/PythonQtSignalReceiver.cpp +++ b/src/PythonQtSignalReceiver.cpp @@ -213,6 +213,7 @@ bool PythonQtSignalReceiver::removeSignalHandler(const char* signal, PyObject* c if (callable) { while (i.hasNext()) { if (i.next().isSame(sigId, callable)) { + QMetaObject::disconnect(_obj, sigId, this, i.value().slotId()); i.remove(); foundCount++; break; @@ -221,6 +222,7 @@ bool PythonQtSignalReceiver::removeSignalHandler(const char* signal, PyObject* c } else { while (i.hasNext()) { if (i.next().signalId() == sigId) { + QMetaObject::disconnect(_obj, sigId, this, i.value().slotId()); i.remove(); foundCount++; } From fd6082dc41db7e894dbddc7002f86ce40f9effdb Mon Sep 17 00:00:00 2001 From: florianlink Date: Thu, 4 Jun 2015 15:18:30 +0000 Subject: [PATCH 13/28] fixed test git-svn-id: http://svn.code.sf.net/p/pythonqt/code/trunk@399 ea8d5007-eb21-0410-b261-ccb3ea6e24a9 --- tests/PythonQtTests.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/PythonQtTests.cpp b/tests/PythonQtTests.cpp index 91f95b38..801198dd 100644 --- a/tests/PythonQtTests.cpp +++ b/tests/PythonQtTests.cpp @@ -465,9 +465,11 @@ void PythonQtTestApi::initTestCase() void PythonQtTestApi::testProperties() { PythonQtObjectPtr main = PythonQt::self()->getMainModule(); +#ifdef PYTHONQT_SUPPORT_NAME_PROPERTY // check for name alias (for backward comp to Qt3) main.evalScript("obj.name = 'hello'"); QVERIFY(QString("hello") == main.getVariable("obj.name").toString()); +#endif main.evalScript("obj.objectName = 'hello2'"); QVERIFY(QString("hello2") == main.getVariable("obj.objectName").toString()); From 857a7df82205f765abe7d4c2a45fd50bf47864b6 Mon Sep 17 00:00:00 2001 From: florianlink Date: Thu, 18 Jun 2015 11:24:39 +0000 Subject: [PATCH 14/28] initial version that handles qualified virtual calls better git-svn-id: http://svn.code.sf.net/p/pythonqt/code/trunk@400 ea8d5007-eb21-0410-b261-ccb3ea6e24a9 --- generator/shellheadergenerator.cpp | 91 +++++++++++++++++++++++------- generator/shellheadergenerator.h | 3 + generator/shellimplgenerator.cpp | 2 +- generator/typesystem_gui.xml | 1 - 4 files changed, 76 insertions(+), 21 deletions(-) diff --git a/generator/shellheadergenerator.cpp b/generator/shellheadergenerator.cpp index f5732e35..50253e6a 100644 --- a/generator/shellheadergenerator.cpp +++ b/generator/shellheadergenerator.cpp @@ -198,6 +198,7 @@ void ShellHeaderGenerator::write(QTextStream &s, const AbstractMetaClass *meta_c } foreach(AbstractMetaFunction* fun, promoteFunctions) { + // normal promoter if (fun->isStatic()) { s << "static "; } @@ -210,26 +211,37 @@ void ShellHeaderGenerator::write(QTextStream &s, const AbstractMetaClass *meta_c if (fun->type()) { s << "return "; } - if (!fun->isAbstract()) { - s << meta_class->qualifiedCppName() << "::"; - } - else { - s << "this->"; - } + // always do a direct call, since we want to call the real virtual function here + s << "this->"; s << fun->originalName() << "("; - for (int i = 0; i < args.size(); ++i) { - if (i > 0) { - s << ", "; + writePromoterArgs(args, s); + s << "); }" << endl; + } + + foreach(AbstractMetaFunction* fun, promoteFunctions) { + // qualified promoter for virtual functions + if (fun->isVirtual()) { + s << "inline "; + writeFunctionSignature(s, fun, 0, "py_qualified_", + Option(IncludeDefaultExpression | OriginalName | UnderscoreSpaces | ProtectedEnumAsInts)); + s << " { "; + QString scriptFunctionName = fun->originalName(); + AbstractMetaArgumentList args = fun->arguments(); + if (fun->type()) { + s << "return "; } - if (args.at(i)->type()->isEnum()) { - AbstractMetaEnum* enumType = m_classes.findEnum((EnumTypeEntry *)args.at(i)->type()->typeEntry()); - if (enumType && enumType->wasProtected()) { - s << "(" << enumType->typeEntry()->qualifiedCppName() << ")"; - } + if (!fun->isAbstract()) { + // call the qualified version, we don't want the virtual function + s << meta_class->qualifiedCppName() << "::"; } - s << args.at(i)->argumentName(); + else { + // TODO: this would better be empty and do no call at all... + s << "this->"; + } + s << fun->originalName() << "("; + writePromoterArgs(args, s); + s << "); }" << endl; } - s << "); }" << endl; } s << "};" << endl << endl; @@ -338,16 +350,41 @@ void ShellHeaderGenerator::write(QTextStream &s, const AbstractMetaClass *meta_c AbstractMetaFunctionList functions = getFunctionsToWrap(meta_class); foreach (const AbstractMetaFunction *function, functions) { - if (!function->isSlot() || function->isVirtual()) { - + if (!function->isSlot()) { // for debugging: //functionHasNonConstReferences(function); - s << " "; writeFunctionSignature(s, function, 0, QString(), Option(AddOwnershipTemplates | ConvertReferenceToPtr | FirstArgIsWrappedObject | IncludeDefaultExpression | OriginalName | ShowStatic | UnderscoreSpaces | ProtectedEnumAsInts)); s << ";" << endl; } + if (function->isVirtual()) { + // qualified version that calls the promoter/the qualified version + s << " "; + writeFunctionSignature(s, function, 0, "py_qualified_", + Option(AddOwnershipTemplates | ConvertReferenceToPtr | FirstArgIsWrappedObject | IncludeDefaultExpression | OriginalName | ShowStatic | UnderscoreSpaces | ProtectedEnumAsInts)); + s << "{ "; + + QString scriptFunctionName = function->originalName(); + AbstractMetaArgumentList args = function->arguments(); + // call the C++ implementation + if (function->type()) { + s << "return "; + // call the C++ implementation + if (function->type()->isReference()) { + s << "&"; + } + } + s << "(((" << promoterClassName(meta_class) << "*)theWrappedObject)->py_qualified_"; + s << function->originalName() << "("; + for (int i = 0; i < args.size(); ++i) { + if (i > 0) + s << ", "; + s << args.at(i)->argumentName(); + } + s << "));"; + s << "}" << endl; + } } if (meta_class->hasDefaultToStringFunction() || meta_class->hasToStringCapability()) { s << " QString py_toString(" << meta_class->qualifiedCppName() << "*);" << endl; @@ -380,6 +417,22 @@ void ShellHeaderGenerator::write(QTextStream &s, const AbstractMetaClass *meta_c } +void ShellHeaderGenerator::writePromoterArgs(AbstractMetaArgumentList &args, QTextStream & s) +{ + for (int i = 0; i < args.size(); ++i) { + if (i > 0) { + s << ", "; + } + if (args.at(i)->type()->isEnum()) { + AbstractMetaEnum* enumType = m_classes.findEnum((EnumTypeEntry *)args.at(i)->type()->typeEntry()); + if (enumType && enumType->wasProtected()) { + s << "(" << enumType->typeEntry()->qualifiedCppName() << ")"; + } + } + s << args.at(i)->argumentName(); + } +} + void ShellHeaderGenerator::writeInjectedCode(QTextStream &s, const AbstractMetaClass *meta_class, int type, bool recursive) { const AbstractMetaClass *cls = meta_class; diff --git a/generator/shellheadergenerator.h b/generator/shellheadergenerator.h index ac7e159d..a6590f58 100644 --- a/generator/shellheadergenerator.h +++ b/generator/shellheadergenerator.h @@ -60,6 +60,9 @@ class ShellHeaderGenerator : public ShellGenerator virtual QString fileNameForClass(const AbstractMetaClass *cls) const; void write(QTextStream &s, const AbstractMetaClass *meta_class); + + void writePromoterArgs(AbstractMetaArgumentList &args, QTextStream & s); + void writeInjectedCode(QTextStream &s, const AbstractMetaClass *meta_class, int type, bool recursive = false); void writeFieldAccessors(QTextStream &s, const AbstractMetaField *field); diff --git a/generator/shellimplgenerator.cpp b/generator/shellimplgenerator.cpp index c34a0229..bdff6f3d 100644 --- a/generator/shellimplgenerator.cpp +++ b/generator/shellimplgenerator.cpp @@ -248,7 +248,7 @@ void ShellImplGenerator::write(QTextStream &s, const AbstractMetaClass *meta_cla // write member functions for (int i = 0; i < functions.size(); ++i) { AbstractMetaFunction *fun = functions.at(i); - bool needsWrapping = (!fun->isSlot() || fun->isVirtual()); + bool needsWrapping = !fun->isSlot(); if (!needsWrapping) { continue; } diff --git a/generator/typesystem_gui.xml b/generator/typesystem_gui.xml index 6c169ec3..dabd8f5b 100644 --- a/generator/typesystem_gui.xml +++ b/generator/typesystem_gui.xml @@ -2099,7 +2099,6 @@ PyObject* constScanLine(QImage* image, int line) { - From e40bdf91c66ee3a73b44d7b76128b7a0f92fe5e6 Mon Sep 17 00:00:00 2001 From: florianlink Date: Thu, 18 Jun 2015 13:55:29 +0000 Subject: [PATCH 15/28] improved handling of qualified virtual calls git-svn-id: http://svn.code.sf.net/p/pythonqt/code/trunk@401 ea8d5007-eb21-0410-b261-ccb3ea6e24a9 --- generator/abstractmetalang.cpp | 12 --------- generator/shellheadergenerator.cpp | 40 ++++++++++++++++-------------- generator/shellimplgenerator.cpp | 3 ++- 3 files changed, 23 insertions(+), 32 deletions(-) diff --git a/generator/abstractmetalang.cpp b/generator/abstractmetalang.cpp index 58a863b9..eb553921 100644 --- a/generator/abstractmetalang.cpp +++ b/generator/abstractmetalang.cpp @@ -696,18 +696,6 @@ QString AbstractMetaFunction::targetLangSignature(bool minimal) const // Attributes... if (!minimal) { -#if 0 // jambi - if (isPublic()) s += "public "; - else if (isProtected()) s += "protected "; - else if (isPrivate()) s += "private "; - -// if (isNative()) s += "native "; -// else - if (isFinalInTargetLang()) s += "final "; - else if (isAbstract()) s += "abstract "; - - if (isStatic()) s += "static "; -#endif // Return type if (type()) s += type()->name() + " "; diff --git a/generator/shellheadergenerator.cpp b/generator/shellheadergenerator.cpp index 50253e6a..8060aeb6 100644 --- a/generator/shellheadergenerator.cpp +++ b/generator/shellheadergenerator.cpp @@ -199,30 +199,32 @@ void ShellHeaderGenerator::write(QTextStream &s, const AbstractMetaClass *meta_c foreach(AbstractMetaFunction* fun, promoteFunctions) { // normal promoter - if (fun->isStatic()) { - s << "static "; - } - s << "inline "; - writeFunctionSignature(s, fun, 0, "promoted_", - Option(IncludeDefaultExpression | OriginalName | UnderscoreSpaces | ProtectedEnumAsInts)); - s << " { "; - QString scriptFunctionName = fun->originalName(); - AbstractMetaArgumentList args = fun->arguments(); - if (fun->type()) { - s << "return "; + if (fun->wasProtected()) { + if (fun->isStatic()) { + s << "static "; + } + s << "inline "; + writeFunctionSignature(s, fun, 0, "promoted_", + Option(IncludeDefaultExpression | OriginalName | UnderscoreSpaces | ProtectedEnumAsInts)); + s << " { "; + QString scriptFunctionName = fun->originalName(); + AbstractMetaArgumentList args = fun->arguments(); + if (fun->type()) { + s << "return "; + } + // always do a direct call, since we want to call the real virtual function here + s << "this->"; + s << fun->originalName() << "("; + writePromoterArgs(args, s); + s << "); }" << endl; } - // always do a direct call, since we want to call the real virtual function here - s << "this->"; - s << fun->originalName() << "("; - writePromoterArgs(args, s); - s << "); }" << endl; } foreach(AbstractMetaFunction* fun, promoteFunctions) { // qualified promoter for virtual functions if (fun->isVirtual()) { s << "inline "; - writeFunctionSignature(s, fun, 0, "py_qualified_", + writeFunctionSignature(s, fun, 0, "py_q_", Option(IncludeDefaultExpression | OriginalName | UnderscoreSpaces | ProtectedEnumAsInts)); s << " { "; QString scriptFunctionName = fun->originalName(); @@ -361,7 +363,7 @@ void ShellHeaderGenerator::write(QTextStream &s, const AbstractMetaClass *meta_c if (function->isVirtual()) { // qualified version that calls the promoter/the qualified version s << " "; - writeFunctionSignature(s, function, 0, "py_qualified_", + writeFunctionSignature(s, function, 0, "py_q_", Option(AddOwnershipTemplates | ConvertReferenceToPtr | FirstArgIsWrappedObject | IncludeDefaultExpression | OriginalName | ShowStatic | UnderscoreSpaces | ProtectedEnumAsInts)); s << "{ "; @@ -375,7 +377,7 @@ void ShellHeaderGenerator::write(QTextStream &s, const AbstractMetaClass *meta_c s << "&"; } } - s << "(((" << promoterClassName(meta_class) << "*)theWrappedObject)->py_qualified_"; + s << "(((" << promoterClassName(meta_class) << "*)theWrappedObject)->py_q_"; s << function->originalName() << "("; for (int i = 0; i < args.size(); ++i) { if (i > 0) diff --git a/generator/shellimplgenerator.cpp b/generator/shellimplgenerator.cpp index bdff6f3d..60a1df1c 100644 --- a/generator/shellimplgenerator.cpp +++ b/generator/shellimplgenerator.cpp @@ -294,7 +294,8 @@ void ShellImplGenerator::write(QTextStream &s, const AbstractMetaClass *meta_cla s << meta_class->qualifiedCppName() << "::"; } } else { - if (fun->wasProtected() || (fun->isVirtual() && meta_class->typeEntry()->shouldCreatePromoter())) { + if (fun->wasProtected()) { + //|| (fun->isVirtual() && meta_class->typeEntry()->shouldCreatePromoter())) { s << " ((" << promoterClassName(meta_class) << "*)theWrappedObject)->promoted_"; } else { s << " theWrappedObject->"; From 0cb64a5ea992c55ecc0ba74b8ab7ab51701c666c Mon Sep 17 00:00:00 2001 From: florianlink Date: Thu, 18 Jun 2015 13:57:06 +0000 Subject: [PATCH 16/28] improved handling of qualified virtual calls git-svn-id: http://svn.code.sf.net/p/pythonqt/code/trunk@402 ea8d5007-eb21-0410-b261-ccb3ea6e24a9 --- src/PythonQtClassWrapper.cpp | 15 +++++++++++++-- src/PythonQtMethodInfo.cpp | 9 ++++++++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/PythonQtClassWrapper.cpp b/src/PythonQtClassWrapper.cpp index 0d31fe8c..92b5070b 100644 --- a/src/PythonQtClassWrapper.cpp +++ b/src/PythonQtClassWrapper.cpp @@ -512,8 +512,19 @@ static PyObject *PythonQtClassWrapper_getattro(PyObject *obj, PyObject *name) Py_INCREF(enumWrapper); return enumWrapper; } else if (member._type == PythonQtMemberInfo::Slot) { - // we return all slots, even the instance slots, since they are callable as unbound slots with self argument - return PythonQtSlotFunction_New(member._slot, obj, NULL); + // NOTE: this does an extra lookup and string copy, it might be better to move this to + // PythonQtClassInfo and add a new cache for qualified class methods... + QByteArray qualifiedMemberName = "py_q_"; + qualifiedMemberName += attributeName; + PythonQtMemberInfo qualifiedMember = wrapper->classInfo()->member(qualifiedMemberName); + if (qualifiedMember._type == PythonQtMemberInfo::Slot) { + // return the qualified member, so that virtual calls on classes call the qualified member + return PythonQtSlotFunction_New(qualifiedMember._slot, obj, NULL); + } + else { + // we return all slots, even the instance slots, since they are callable as unbound slots with self argument + return PythonQtSlotFunction_New(member._slot, obj, NULL); + } } else if (member._type == PythonQtMemberInfo::Signal) { // we return all signals, even the instance signals, since they are callable as unbound signals with self argument return PythonQtSignalFunction_New(member._slot, obj, NULL); diff --git a/src/PythonQtMethodInfo.cpp b/src/PythonQtMethodInfo.cpp index e7f79bde..716fd648 100644 --- a/src/PythonQtMethodInfo.cpp +++ b/src/PythonQtMethodInfo.cpp @@ -401,7 +401,11 @@ QString PythonQtSlotInfo::fullSignature(bool skipReturnValue, int optionalArgsIn if (sig.startsWith("new_")) { sig = sig.mid(4); isConstructor = true; - } else if (sig.startsWith("delete_")) { + } + else if (sig.startsWith("py_q_")) { + sig = sig.mid(5); + } + else if (sig.startsWith("delete_")) { sig = sig.mid(7); isDestructor = true; } else if(sig.startsWith("static_")) { @@ -471,6 +475,9 @@ QByteArray PythonQtSlotInfo::slotName(bool removeDecorators) const { QByteArray name = PythonQtUtils::methodName(_meta); if (removeDecorators) { + if (name.startsWith("py_q_")) { + name = name.mid(5); + } else if (name.startsWith("static_")) { name = name.mid(7); int idx = name.indexOf("_"); From dbeb4753a09737578667f5a7cf91f42d4f8fbc5e Mon Sep 17 00:00:00 2001 From: florianlink Date: Thu, 18 Jun 2015 14:45:51 +0000 Subject: [PATCH 17/28] removed generating wrappers for virtual functions that are already declared in a base class git-svn-id: http://svn.code.sf.net/p/pythonqt/code/trunk@403 ea8d5007-eb21-0410-b261-ccb3ea6e24a9 --- generator/shellgenerator.cpp | 12 ++++++++++++ generator/shellgenerator.h | 2 ++ generator/shellheadergenerator.cpp | 2 +- generator/shellimplgenerator.cpp | 2 +- 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/generator/shellgenerator.cpp b/generator/shellgenerator.cpp index 05875180..415901f5 100644 --- a/generator/shellgenerator.cpp +++ b/generator/shellgenerator.cpp @@ -297,6 +297,18 @@ bool ShellGenerator::functionHasNonConstReferences(const AbstractMetaFunction* f return false; } +bool ShellGenerator::functionNeedsNormalWrapperSlot(const AbstractMetaFunction* func, const AbstractMetaClass* currentClass) +{ + if (func->isSlot()) { + return false; + } + else if (func->isVirtual()) { + return func->declaringClass() == currentClass; + } else { + return true; + } +} + AbstractMetaFunctionList ShellGenerator::getFunctionsToWrap(const AbstractMetaClass* meta_class) { AbstractMetaFunctionList functions = meta_class->queryFunctions( diff --git a/generator/shellgenerator.h b/generator/shellgenerator.h index e2d0283f..58097e1d 100644 --- a/generator/shellgenerator.h +++ b/generator/shellgenerator.h @@ -77,6 +77,8 @@ class ShellGenerator : public Generator bool functionHasNonConstReferences(const AbstractMetaFunction* func); + bool functionNeedsNormalWrapperSlot(const AbstractMetaFunction* func, const AbstractMetaClass* currentClass); + static QString shellClassName(const AbstractMetaClass *meta_class) { return "PythonQtShell_" + meta_class->name(); } diff --git a/generator/shellheadergenerator.cpp b/generator/shellheadergenerator.cpp index 8060aeb6..ad7031b8 100644 --- a/generator/shellheadergenerator.cpp +++ b/generator/shellheadergenerator.cpp @@ -352,7 +352,7 @@ void ShellHeaderGenerator::write(QTextStream &s, const AbstractMetaClass *meta_c AbstractMetaFunctionList functions = getFunctionsToWrap(meta_class); foreach (const AbstractMetaFunction *function, functions) { - if (!function->isSlot()) { + if (functionNeedsNormalWrapperSlot(function, meta_class)) { // for debugging: //functionHasNonConstReferences(function); s << " "; diff --git a/generator/shellimplgenerator.cpp b/generator/shellimplgenerator.cpp index 60a1df1c..1982a3a7 100644 --- a/generator/shellimplgenerator.cpp +++ b/generator/shellimplgenerator.cpp @@ -248,7 +248,7 @@ void ShellImplGenerator::write(QTextStream &s, const AbstractMetaClass *meta_cla // write member functions for (int i = 0; i < functions.size(); ++i) { AbstractMetaFunction *fun = functions.at(i); - bool needsWrapping = !fun->isSlot(); + bool needsWrapping = functionNeedsNormalWrapperSlot(fun, meta_class); if (!needsWrapping) { continue; } From 98d1c58a3cf27d6c632a15e7ab4f95e75435644a Mon Sep 17 00:00:00 2001 From: Max Smolens Date: Tue, 1 Sep 2015 09:20:57 -0400 Subject: [PATCH 18/28] Enable "name" property support Prior to commit https://github.com/commontk/PythonQt/commit/9c2e489d734758cd63bb7cbe4a0ed6ae6c6ce228, the "name" property was offered as an alias for the "objectName" property. Now, the alias is a compile-time option that is disabled by default. This commit enables the "name" property alias to maintain backwards compatibility with earlier versions. --- CMakeLists.txt | 731 +++++++++++++++++++++++++------------------------ 1 file changed, 366 insertions(+), 365 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 668af80b..ee194473 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,365 +1,366 @@ -#----------------------------------------------------------------------------- -# 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 2.8) - -#----------------------------------------------------------------------------- -project(PythonQt) -#----------------------------------------------------------------------------- - -include(CTestUseLaunchers OPTIONAL) - -#---------------------------------------------------------------------------- -# Qt version - -set(PythonQt_QT_VERSION 5 CACHE STRING "Pick a version of Qt to use: 4 or 5") - -set(minimum_required_qt5_version "5.3.0") -set(minimum_required_qt4_version "4.6.2") - -#----------------------------------------------------------------------------- -# Python libraries - -find_package(PythonLibs REQUIRED) -include_directories("${PYTHON_INCLUDE_DIR}") -add_definitions(-DPYTHONQT_USE_RELEASE_PYTHON_FALLBACK) - -#----------------------------------------------------------------------------- -# Build options -option(PythonQt_Wrap_QtAll "Make all Qt components available in python" OFF) - -if(PythonQt_QT_VERSION MATCHES 4) - set(qtlibs core gui network opengl sql svg uitools webkit xml xmlpatterns locale) -else() - set(qtlibs Core Network OpenGL Sql Svg Widgets WebKitWidgets Xml XmlPatterns UiTools) -endif() - -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() - -option(PythonQt_Wrap_QtAll "Make all Qt components available in python" OFF) - -foreach(qtlib ${qtlibs}) - OPTION(PythonQt_Wrap_Qt${qtlib} "Make all of Qt${qtlib} available in python" OFF) -endforeach() - -# Force option if it applies -if(PythonQt_Wrap_QtAll) - list(REMOVE_ITEM qtlibs XmlPatterns) # xmlpatterns wrapper does *NOT* build at all :( - foreach(qtlib ${qtlibs}) - if(NOT ${PythonQt_Wrap_Qt${qtlib}}) - set(PythonQt_Wrap_Qt${qtlib} ON CACHE BOOL "Make all of Qt${qtlib} available in python" FORCE) - message(STATUS "Enabling [PythonQt_Wrap_Qt${qtlib}] 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 - -if(PythonQt_QT_VERSION MATCHES 5) - - if(BUILD_TESTING) - list(APPEND qtlibs Test) - endif() - - find_package(Qt5 ${minimum_required_qt5_version} COMPONENTS ${qtlibs} REQUIRED) - - if(Qt5_DIR) - get_filename_component(_Qt5_DIR "${Qt5_DIR}/../../../" ABSOLUTE) - list(FIND CMAKE_PREFIX_PATH "${_Qt5_DIR}" _result) - if(_result LESS 0) - set(CMAKE_PREFIX_PATH "${_Qt5_DIR};${CMAKE_PREFIX_PATH}" CACHE PATH "" FORCE) - endif() - endif() - - get_target_property(_qmake_exec Qt5::qmake LOCATION) - execute_process(COMMAND ${_qmake_exec} -query QT_INSTALL_BINS - RESULT_VARIABLE _result - OUTPUT_VARIABLE QT_BINARY_DIR - ERROR_VARIABLE _error - ) - string(STRIP "${QT_BINARY_DIR}" QT_BINARY_DIR) - if(_result OR NOT EXISTS "${QT_BINARY_DIR}") - message(FATAL_ERROR "Could not determine Qt binary directory: ${_result} ${QT_BINARY_DIR} ${_error}") - endif() - - set(QT_LIBRARIES ) - foreach(qtlib ${qtlibs}) - include_directories(${Qt5${qtlib}_INCLUDE_DIRS}) - list(APPEND QT_LIBRARIES ${Qt5${qtlib}_LIBRARIES}) - add_definitions(${Qt5${qtlib}_DEFINITIONS}) - endforeach() - - #----------------------------------------------------------------------------- - # The variable "generated_cpp_suffix" allows to conditionnally compile the generated wrappers - # associated with the Qt version being used. - set(generated_cpp_suffix "_${Qt5Core_VERSION_MAJOR}${Qt5Core_VERSION_MINOR}") - - # Use Qt5.4 as default for higher versions like it's done in build/common.prf - if(${Qt5Core_VERSION_MINOR} GREATER 4) - set(generated_cpp_suffix "_${Qt5Core_VERSION_MAJOR}4") - endif() - - -else() - #----------------------------------------------------------------------------- - # Setup Qt4 - - find_package(Qt4) - - if(QT4_FOUND) - - set(found_qt_version ${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}.${QT_VERSION_PATCH}) - - if(${found_qt_version} VERSION_LESS ${minimum_required_qt4_version}) - message(FATAL_ERROR "error: PythonQt requires Qt >= ${minimum_required_qt4_version} -- you cannot use Qt ${found_qt_version}.") - endif() - - # Enable required qt module - foreach(qtlib ${qtlibs}) - string(TOUPPER ${qtlib} qtlib_uppercase) - if (NOT ${QT_QT${qtlib_uppercase}_FOUND}) - message(FATAL_ERROR "QT_QT${${qtlib_uppercase} *not* FOUND - Try to disable PythonQt_Wrap_Qt${qtlib}") - endif() - set(QT_USE_QT${qtlib_uppercase} ${PythonQt_Wrap_Qt${qtlib}}) - endforeach() - - set(QT_USE_QTTEST ${BUILD_TESTING}) - - 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() - - #----------------------------------------------------------------------------- - # The variable "generated_cpp_suffix" allows to conditionnally compile the generated wrappers - # associated with the Qt version being used. - set(generated_cpp_suffix "_${QT_VERSION_MAJOR}${QT_VERSION_MINOR}") - - # TODO: generated headers for Qt4.8 contains several locales that are not available - # out of the box -> force 4.7 - if("${generated_cpp_suffix}" STREQUAL "_46" OR "${generated_cpp_suffix}" STREQUAL "_48") - set(generated_cpp_suffix "_47") # Also use 4.7 wrappers for 4.6.x version - endif() -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/PythonQtQFileImporter.cpp - src/PythonQtSignalReceiver.cpp - src/PythonQtSlot.cpp - src/PythonQtSignal.cpp - src/PythonQtStdDecorators.cpp - src/PythonQtStdIn.cpp - src/PythonQtStdOut.cpp - src/gui/PythonQtScriptingConsole.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/PythonQtQFileImporter.h - src/PythonQtSignalReceiver.h - src/PythonQtSlot.h - src/PythonQtSignal.h - src/PythonQtStdDecorators.h - src/PythonQtStdIn.h - src/PythonQtStdOut.h - src/PythonQtSystem.h - src/PythonQtVariants.h - src/PythonQtPythonInclude.h - src/PythonQtUtils.h -) -if(PythonQt_QT_VERSION MATCHES 4) - set(sources ${sources} generated_cpp${generated_cpp_suffix}/PythonQt_QtBindings.cpp) - set(headers ${headers} generated_cpp${generated_cpp_suffix}/PythonQt_QtBindings.h) -endif() -#----------------------------------------------------------------------------- -# 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}) - - if (${PythonQt_Wrap_Qt${qtlib}}) - - ADD_DEFINITIONS(-DPYTHONQT_WRAP_Qt${qtlib}) - - set(file_prefix generated_cpp${generated_cpp_suffix}/com_trolltech_qt_${qtlib}/com_trolltech_qt_${qtlib}) - - foreach(index RANGE 0 11) - - # 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() - -#----------------------------------------------------------------------------- -# UI files -set(ui_sources ) - -#----------------------------------------------------------------------------- -# Resources -set(qrc_sources ) - -#----------------------------------------------------------------------------- -# Do wrapping -if(PythonQt_QT_VERSION MATCHES 4) - qt4_wrap_cpp(gen_moc_sources ${moc_sources}) - qt4_wrap_ui(gen_ui_sources ${ui_sources}) - qt4_add_resources(gen_qrc_sources ${qrc_sources}) -else() - qt5_wrap_cpp(gen_moc_sources ${moc_sources}) - qt5_wrap_ui(gen_ui_sources ${ui_sources}) - qt5_add_resources(gen_qrc_sources ${qrc_sources}) -endif() -#----------------------------------------------------------------------------- -# Build the library - -include_directories( - ${CMAKE_CURRENT_SOURCE_DIR}/src - ) - -add_library(PythonQt SHARED - ${sources} - ${gen_moc_sources} - ${gen_ui_sources} - ${gen_qrc_sources} - ) -set_target_properties(PythonQt PROPERTIES DEFINE_SYMBOL PYTHONQT_EXPORTS) - -# -# That should solve linkage error on Mac when the project is used in a superbuild setup -# See http://blog.onesadcookie.com/2008/01/installname-magic.html -# -set_target_properties(PythonQt PROPERTIES - INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib" - ) - -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 - ) - - list(APPEND test_sources - tests/PythonQtTests.cpp - tests/PythonQtTests.h - ) - if(PythonQt_QT_VERSION MATCHES 4) - QT4_WRAP_CPP(test_sources - tests/PythonQtTests.h - ) - else() - QT5_WRAP_CPP(test_sources - tests/PythonQtTests.h - ) - endif() - - set_property(SOURCE tests/PythonQtTestMain.cpp PROPERTY COMPILE_DEFINITIONS "main=tests_PythonQtTestMain") - - add_executable(PythonQtCppTests ${test_sources}) - target_link_libraries(PythonQtCppTests PythonQt ${Qt5Test_LIBRARIES}) - - add_test( - NAME tests_PythonQtTestMain - COMMAND ${Slicer_LAUNCH_COMMAND} $ tests/PythonQtTestMain - ) -endif() - +#----------------------------------------------------------------------------- +# 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 2.8) + +#----------------------------------------------------------------------------- +project(PythonQt) +#----------------------------------------------------------------------------- + +include(CTestUseLaunchers OPTIONAL) + +#---------------------------------------------------------------------------- +# Qt version + +set(PythonQt_QT_VERSION 5 CACHE STRING "Pick a version of Qt to use: 4 or 5") + +set(minimum_required_qt5_version "5.3.0") +set(minimum_required_qt4_version "4.6.2") + +#----------------------------------------------------------------------------- +# Python libraries + +find_package(PythonLibs REQUIRED) +include_directories("${PYTHON_INCLUDE_DIR}") +add_definitions(-DPYTHONQT_USE_RELEASE_PYTHON_FALLBACK) + +#----------------------------------------------------------------------------- +# Build options +option(PythonQt_Wrap_QtAll "Make all Qt components available in python" OFF) + +if(PythonQt_QT_VERSION MATCHES 4) + set(qtlibs core gui network opengl sql svg uitools webkit xml xmlpatterns locale) +else() + set(qtlibs Core Network OpenGL Sql Svg Widgets WebKitWidgets Xml XmlPatterns UiTools) +endif() + +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() + +option(PythonQt_Wrap_QtAll "Make all Qt components available in python" OFF) + +foreach(qtlib ${qtlibs}) + OPTION(PythonQt_Wrap_Qt${qtlib} "Make all of Qt${qtlib} available in python" OFF) +endforeach() + +# Force option if it applies +if(PythonQt_Wrap_QtAll) + list(REMOVE_ITEM qtlibs XmlPatterns) # xmlpatterns wrapper does *NOT* build at all :( + foreach(qtlib ${qtlibs}) + if(NOT ${PythonQt_Wrap_Qt${qtlib}}) + set(PythonQt_Wrap_Qt${qtlib} ON CACHE BOOL "Make all of Qt${qtlib} available in python" FORCE) + message(STATUS "Enabling [PythonQt_Wrap_Qt${qtlib}] 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 + +if(PythonQt_QT_VERSION MATCHES 5) + + if(BUILD_TESTING) + list(APPEND qtlibs Test) + endif() + + find_package(Qt5 ${minimum_required_qt5_version} COMPONENTS ${qtlibs} REQUIRED) + + if(Qt5_DIR) + get_filename_component(_Qt5_DIR "${Qt5_DIR}/../../../" ABSOLUTE) + list(FIND CMAKE_PREFIX_PATH "${_Qt5_DIR}" _result) + if(_result LESS 0) + set(CMAKE_PREFIX_PATH "${_Qt5_DIR};${CMAKE_PREFIX_PATH}" CACHE PATH "" FORCE) + endif() + endif() + + get_target_property(_qmake_exec Qt5::qmake LOCATION) + execute_process(COMMAND ${_qmake_exec} -query QT_INSTALL_BINS + RESULT_VARIABLE _result + OUTPUT_VARIABLE QT_BINARY_DIR + ERROR_VARIABLE _error + ) + string(STRIP "${QT_BINARY_DIR}" QT_BINARY_DIR) + if(_result OR NOT EXISTS "${QT_BINARY_DIR}") + message(FATAL_ERROR "Could not determine Qt binary directory: ${_result} ${QT_BINARY_DIR} ${_error}") + endif() + + set(QT_LIBRARIES ) + foreach(qtlib ${qtlibs}) + include_directories(${Qt5${qtlib}_INCLUDE_DIRS}) + list(APPEND QT_LIBRARIES ${Qt5${qtlib}_LIBRARIES}) + add_definitions(${Qt5${qtlib}_DEFINITIONS}) + endforeach() + + #----------------------------------------------------------------------------- + # The variable "generated_cpp_suffix" allows to conditionnally compile the generated wrappers + # associated with the Qt version being used. + set(generated_cpp_suffix "_${Qt5Core_VERSION_MAJOR}${Qt5Core_VERSION_MINOR}") + + # Use Qt5.4 as default for higher versions like it's done in build/common.prf + if(${Qt5Core_VERSION_MINOR} GREATER 4) + set(generated_cpp_suffix "_${Qt5Core_VERSION_MAJOR}4") + endif() + + +else() + #----------------------------------------------------------------------------- + # Setup Qt4 + + find_package(Qt4) + + if(QT4_FOUND) + + set(found_qt_version ${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}.${QT_VERSION_PATCH}) + + if(${found_qt_version} VERSION_LESS ${minimum_required_qt4_version}) + message(FATAL_ERROR "error: PythonQt requires Qt >= ${minimum_required_qt4_version} -- you cannot use Qt ${found_qt_version}.") + endif() + + # Enable required qt module + foreach(qtlib ${qtlibs}) + string(TOUPPER ${qtlib} qtlib_uppercase) + if (NOT ${QT_QT${qtlib_uppercase}_FOUND}) + message(FATAL_ERROR "QT_QT${${qtlib_uppercase} *not* FOUND - Try to disable PythonQt_Wrap_Qt${qtlib}") + endif() + set(QT_USE_QT${qtlib_uppercase} ${PythonQt_Wrap_Qt${qtlib}}) + endforeach() + + set(QT_USE_QTTEST ${BUILD_TESTING}) + + 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() + + #----------------------------------------------------------------------------- + # The variable "generated_cpp_suffix" allows to conditionnally compile the generated wrappers + # associated with the Qt version being used. + set(generated_cpp_suffix "_${QT_VERSION_MAJOR}${QT_VERSION_MINOR}") + + # TODO: generated headers for Qt4.8 contains several locales that are not available + # out of the box -> force 4.7 + if("${generated_cpp_suffix}" STREQUAL "_46" OR "${generated_cpp_suffix}" STREQUAL "_48") + set(generated_cpp_suffix "_47") # Also use 4.7 wrappers for 4.6.x version + endif() +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/PythonQtQFileImporter.cpp + src/PythonQtSignalReceiver.cpp + src/PythonQtSlot.cpp + src/PythonQtSignal.cpp + src/PythonQtStdDecorators.cpp + src/PythonQtStdIn.cpp + src/PythonQtStdOut.cpp + src/gui/PythonQtScriptingConsole.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/PythonQtQFileImporter.h + src/PythonQtSignalReceiver.h + src/PythonQtSlot.h + src/PythonQtSignal.h + src/PythonQtStdDecorators.h + src/PythonQtStdIn.h + src/PythonQtStdOut.h + src/PythonQtSystem.h + src/PythonQtVariants.h + src/PythonQtPythonInclude.h + src/PythonQtUtils.h +) +if(PythonQt_QT_VERSION MATCHES 4) + set(sources ${sources} generated_cpp${generated_cpp_suffix}/PythonQt_QtBindings.cpp) + set(headers ${headers} generated_cpp${generated_cpp_suffix}/PythonQt_QtBindings.h) +endif() +#----------------------------------------------------------------------------- +# 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}) + + if (${PythonQt_Wrap_Qt${qtlib}}) + + ADD_DEFINITIONS(-DPYTHONQT_WRAP_Qt${qtlib}) + + set(file_prefix generated_cpp${generated_cpp_suffix}/com_trolltech_qt_${qtlib}/com_trolltech_qt_${qtlib}) + + foreach(index RANGE 0 11) + + # 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() + +#----------------------------------------------------------------------------- +# UI files +set(ui_sources ) + +#----------------------------------------------------------------------------- +# Resources +set(qrc_sources ) + +#----------------------------------------------------------------------------- +# Do wrapping +if(PythonQt_QT_VERSION MATCHES 4) + qt4_wrap_cpp(gen_moc_sources ${moc_sources}) + qt4_wrap_ui(gen_ui_sources ${ui_sources}) + qt4_add_resources(gen_qrc_sources ${qrc_sources}) +else() + qt5_wrap_cpp(gen_moc_sources ${moc_sources}) + qt5_wrap_ui(gen_ui_sources ${ui_sources}) + qt5_add_resources(gen_qrc_sources ${qrc_sources}) +endif() +#----------------------------------------------------------------------------- +# Build the library + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/src + ) + +add_library(PythonQt SHARED + ${sources} + ${gen_moc_sources} + ${gen_ui_sources} + ${gen_qrc_sources} + ) +set_target_properties(PythonQt PROPERTIES DEFINE_SYMBOL PYTHONQT_EXPORTS) + +# +# That should solve linkage error on Mac when the project is used in a superbuild setup +# See http://blog.onesadcookie.com/2008/01/installname-magic.html +# +set_target_properties(PythonQt PROPERTIES + INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib" + ) + +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 + ) + + list(APPEND test_sources + tests/PythonQtTests.cpp + tests/PythonQtTests.h + ) + if(PythonQt_QT_VERSION MATCHES 4) + QT4_WRAP_CPP(test_sources + tests/PythonQtTests.h + ) + else() + QT5_WRAP_CPP(test_sources + tests/PythonQtTests.h + ) + endif() + + set_property(SOURCE tests/PythonQtTestMain.cpp PROPERTY COMPILE_DEFINITIONS "main=tests_PythonQtTestMain") + + add_executable(PythonQtCppTests ${test_sources}) + target_link_libraries(PythonQtCppTests PythonQt ${Qt5Test_LIBRARIES}) + + add_test( + NAME tests_PythonQtTestMain + COMMAND ${Slicer_LAUNCH_COMMAND} $ tests/PythonQtTestMain + ) +endif() + + From e90a69017cb7c0cd39f81ebc66e6fc7c722bf704 Mon Sep 17 00:00:00 2001 From: Max Smolens Date: Fri, 4 Sep 2015 15:36:00 -0400 Subject: [PATCH 19/28] Update README.md to describe new commits --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 841026d3..9a37e583 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Prerequisites Build instructions ------------------ -By default, the `patched-3` version will be checked out. +By default, the `patched-5` version will be checked out. ``` git clone git://github.com/commontk/PythonQt.git @@ -46,7 +46,9 @@ Available branches This repository contains 5 branches: ### patched-5 -* Based on patched-4 + [r395](http://sourceforge.net/p/pythonqt/code/395/) +* Based on patched-4 + [r403](http://sourceforge.net/p/pythonqt/code/403/) excluding commit [r397](http://sourceforge.net/p/pythonqt/code/397/) +* List of bug fixes: + * Fix for memory leaks and cleanup crash * List of features: * CMake: * Fix install rules From 039d785275ff90fc7c44899c45743d4c0a76840f Mon Sep 17 00:00:00 2001 From: Max Smolens Date: Fri, 11 Sep 2015 09:17:59 -0400 Subject: [PATCH 20/28] Prevent crashes during and after cleanup This commit prevents crashes by handling scenarios such as: (a) object destruction after the Python interpreter has been finalized (b) object destruction after cleanup, i.e. the singleton no longer exists Any usage of a Qt enum demonstrates (a). One example that demonstrates (b) is a QTimer object which is created with a QApplication parent. PythonQt::cleanup() is called before the QApplication is completely destroyed, so the code that handles wrapping the QTimer object must handle the case when the PythonQt singleton no longer exists. Co-authored-by: Jean-Christophe Fillion-Robin --- src/PythonQt.h | 2 +- src/PythonQtObjectPtr.cpp | 2 +- src/PythonQtSignalReceiver.cpp | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/PythonQt.h b/src/PythonQt.h index 01ef8206..27130b54 100644 --- a/src/PythonQt.h +++ b/src/PythonQt.h @@ -526,7 +526,7 @@ class PYTHONQT_EXPORT PythonQt : public QObject { //@{ //! get access to internal data (should not be used on the public API, but is used by some C functions) - static PythonQtPrivate* priv() { return _self->_p; } + static PythonQtPrivate* priv() { return _self ? _self->_p : NULL; } //! clear all NotFound entries on all class infos, to ensure that //! newly loaded wrappers can add methods even when the object was wrapped by PythonQt before the wrapper was loaded diff --git a/src/PythonQtObjectPtr.cpp b/src/PythonQtObjectPtr.cpp index 95fb4e0f..2d79a5bb 100644 --- a/src/PythonQtObjectPtr.cpp +++ b/src/PythonQtObjectPtr.cpp @@ -49,7 +49,7 @@ PythonQtObjectPtr::PythonQtObjectPtr(PyObject* o) PythonQtObjectPtr::~PythonQtObjectPtr() { - if (_object) Py_DECREF(_object); + if (_object && Py_IsInitialized()) Py_DECREF(_object); } void PythonQtObjectPtr::setNewRef(PyObject* o) diff --git a/src/PythonQtSignalReceiver.cpp b/src/PythonQtSignalReceiver.cpp index d81ab176..e3ac27f2 100644 --- a/src/PythonQtSignalReceiver.cpp +++ b/src/PythonQtSignalReceiver.cpp @@ -172,7 +172,9 @@ PythonQtSignalReceiver::PythonQtSignalReceiver(QObject* obj):PythonQtSignalRecei PythonQtSignalReceiver::~PythonQtSignalReceiver() { - PythonQt::priv()->removeSignalEmitter(_obj); + if (PythonQt::priv()) { + PythonQt::priv()->removeSignalEmitter(_obj); + } } From a636d5a449d23df641764228cbec438a21663e08 Mon Sep 17 00:00:00 2001 From: Max Smolens Date: Fri, 11 Sep 2015 10:06:45 -0400 Subject: [PATCH 21/28] Fix tests link error on Windows This commit fixes a link error building PythonQtCppTests on Windows: 1>PythonQtCppTests.obj : error LNK2001: unresolved external symbol "int __cdecl tests_PythonQtTestMain(int,char * * const)" (?tests_PythonQtTestMain@@YAHHQEAPEAD@Z) 1>C:\temp\PythonQt-build\Debug\PythonQtCppTests.exe : fatal error LNK1120: 1 unresolved externals --- tests/PythonQtTestMain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PythonQtTestMain.cpp b/tests/PythonQtTestMain.cpp index 44f5bea6..303ac0d0 100644 --- a/tests/PythonQtTestMain.cpp +++ b/tests/PythonQtTestMain.cpp @@ -44,7 +44,7 @@ #include -int main( int argc, char **argv ) +int main(int argc, char *argv[]) { QApplication qapp(argc, argv); From 9245264eb06ac22f8cb83645b89a410dc0e08a20 Mon Sep 17 00:00:00 2001 From: Max Smolens Date: Fri, 11 Sep 2015 16:23:24 -0400 Subject: [PATCH 22/28] Fix refcount problems seen when re-initializing Python after finalizing A sequence of calls like the following would crash in Python when reinitializing the interpreter the second time: PythonQt::init(0); ... Py_Finalize(); PythonQt::init(0); ... Py_Finalize(); --- src/PythonQt.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/PythonQt.cpp b/src/PythonQt.cpp index 9cbcfba3..04e2fa81 100644 --- a/src/PythonQt.cpp +++ b/src/PythonQt.cpp @@ -657,6 +657,7 @@ PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtCla PyObject* className = PyString_FromString(pythonClassName.constData()); PyObject* baseClasses = PyTuple_New(1); + Py_INCREF(&PythonQtInstanceWrapper_Type); PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PythonQtInstanceWrapper_Type); PyObject* typeDict = PyDict_New(); @@ -1611,6 +1612,7 @@ void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQ #endif _p->_pythonQtModuleName = name; + Py_INCREF(&PythonQtBoolResult_Type); PyModule_AddObject(_p->pythonQtModule().object(), "BoolResult", (PyObject*)&PythonQtBoolResult_Type); PythonQtObjectPtr sys; sys.setNewRef(PyImport_ImportModule("sys")); @@ -1634,7 +1636,9 @@ void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQ Py_ssize_t old_size = PyTuple_Size(old_module_names); PyObject *module_names = PyTuple_New(old_size + 1); for (Py_ssize_t i = 0; i < old_size; i++) { - PyTuple_SetItem(module_names, i, PyTuple_GetItem(old_module_names, i)); + PyObject *item = PyTuple_GetItem(old_module_names, i); + Py_INCREF(item); + PyTuple_SetItem(module_names, i, item); } PyTuple_SetItem(module_names, old_size, PyString_FromString(name.constData())); PyModule_AddObject(sys.object(), "builtin_module_names", module_names); From e41b773cef866c1a092e47829701f799c1ea84ac Mon Sep 17 00:00:00 2001 From: Max Smolens Date: Fri, 11 Sep 2015 16:31:48 -0400 Subject: [PATCH 23/28] Explicitly initialize global storage containers This commit changes initialization of the global storage containers to be explicit instead of happening during static initialization. This makes the containers properly initialized if PythonQt is initialized and cleaned up more than once. The motivation for this change is to support testing cleanup and finalization. --- src/PythonQt.cpp | 4 ++++ src/PythonQtMisc.h | 15 ++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/PythonQt.cpp b/src/PythonQt.cpp index 04e2fa81..d4443528 100644 --- a/src/PythonQt.cpp +++ b/src/PythonQt.cpp @@ -1294,6 +1294,10 @@ PythonQtPrivate::PythonQtPrivate() _hadError = false; _systemExitExceptionHandlerEnabled = false; _debugAPI = new PythonQtDebugAPI(this); + + PythonQtConv::global_valueStorage.init(); + PythonQtConv::global_ptrStorage.init(); + PythonQtConv::global_variantStorage.init(); } void PythonQtPrivate::setupSharedLibrarySuffixes() diff --git a/src/PythonQtMisc.h b/src/PythonQtMisc.h index 2c75c456..65b58878 100644 --- a/src/PythonQtMisc.h +++ b/src/PythonQtMisc.h @@ -76,12 +76,25 @@ template class PythonQtValueStorage PythonQtValueStorage() { _chunkIdx = 0; _chunkOffset = 0; + _currentChunk = NULL; + }; + + //! initialize memory + void init() { + assert(_currentChunk == NULL); + assert(_chunks.isEmpty()); + _chunkIdx = 0; + _chunkOffset = 0; _currentChunk = new T[chunkEntries]; _chunks.append(_currentChunk); - }; + } //! clear all memory void clear() { + _chunkIdx = 0; + _chunkOffset = 0; + _currentChunk = NULL; + T* chunk; Q_FOREACH(chunk, _chunks) { delete[]chunk; From 81e51e416dc70eb236e4aa0fcd8343d0f503c96b Mon Sep 17 00:00:00 2001 From: Max Smolens Date: Fri, 11 Sep 2015 16:36:51 -0400 Subject: [PATCH 24/28] Add cleanup/finalization tests Add tests that check for clean cleanup and finalization in different scenarios. Co-authored-by: Jean-Christophe Fillion-Robin Co-authored-by: Pat Marion --- CMakeLists.txt | 12 ++++++ tests/PythonQtTestCleanup.cpp | 69 +++++++++++++++++++++++++++++++++++ tests/PythonQtTestCleanup.h | 45 +++++++++++++++++++++++ tests/PythonQtTestMain.cpp | 8 ++++ 4 files changed, 134 insertions(+) create mode 100644 tests/PythonQtTestCleanup.cpp create mode 100644 tests/PythonQtTestCleanup.h diff --git a/CMakeLists.txt b/CMakeLists.txt index ee194473..fdc15423 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -352,6 +352,18 @@ if(BUILD_TESTING) ) endif() + if(PythonQt_Wrap_Qtcore) + include_directories(generated_cpp${generated_cpp_suffix}) + + list(APPEND test_sources + tests/PythonQtTestCleanup.cpp + tests/PythonQtTestCleanup.h + ) + QT4_WRAP_CPP(test_sources + tests/PythonQtTestCleanup.h + ) + endif() + set_property(SOURCE tests/PythonQtTestMain.cpp PROPERTY COMPILE_DEFINITIONS "main=tests_PythonQtTestMain") add_executable(PythonQtCppTests ${test_sources}) diff --git a/tests/PythonQtTestCleanup.cpp b/tests/PythonQtTestCleanup.cpp new file mode 100644 index 00000000..796c0eba --- /dev/null +++ b/tests/PythonQtTestCleanup.cpp @@ -0,0 +1,69 @@ +#include "PythonQtTestCleanup.h" +#include "PythonQt.h" +#include "PythonQt_QtBindings.h" + +void PythonQtTestCleanup::initTestCase() +{ +} + +void PythonQtTestCleanup::cleanupTestCase() +{ +} + +void PythonQtTestCleanup::init() +{ + // Initialize before each test + + PythonQt::init(PythonQt::IgnoreSiteModule); + PythonQt_init_QtBindings(); + + _helper = new PythonQtTestCleanupHelper(); + PythonQtObjectPtr main = PythonQt::self()->getMainModule(); + PythonQt::self()->addObject(main, "obj", _helper); +} + +void PythonQtTestCleanup::cleanup() +{ + // Finalize and cleanup after each test + + PythonQtObjectPtr main = PythonQt::self()->getMainModule(); + PythonQt::self()->removeVariable(main, "obj"); + delete _helper; + _helper = NULL; + + if (Py_IsInitialized()) { + Py_Finalize(); + } + + PythonQt::cleanup(); +} + +void PythonQtTestCleanup::testQtEnum() +{ + QVERIFY(_helper->runScript( + "import PythonQt.QtCore\n" \ + "x = PythonQt.QtCore.QFile.ReadOnly\n" \ + "obj.setPassed()" + )); +} + +void PythonQtTestCleanup::testCallQtMethodInDel() +{ + QVERIFY(_helper->runScript( + "import PythonQt.QtCore\n" \ + "class TimerWrapper(object):\n" \ + " def __init__(self):\n" \ + " self.timer = PythonQt.QtCore.QTimer()\n" \ + " def __del__(self):\n" \ + " self.timer.setSingleShot(True)\n" \ + "x = TimerWrapper()\n" \ + "obj.setPassed()\n" + )); +} + +bool PythonQtTestCleanupHelper::runScript(const char* script) +{ + _passed = false; + PyRun_SimpleString(script); + return _passed; +} diff --git a/tests/PythonQtTestCleanup.h b/tests/PythonQtTestCleanup.h new file mode 100644 index 00000000..2c4879e2 --- /dev/null +++ b/tests/PythonQtTestCleanup.h @@ -0,0 +1,45 @@ +#ifndef _PYTHONQTTESTCLEANUP_H +#define _PYTHONQTTESTCLEANUP_H + +#include "PythonQt.h" +#include + +class PythonQtTestCleanupHelper; + +//! Test PythonQt cleanup and Python interpreter finalization +class PythonQtTestCleanup : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + + void testQtEnum(); + void testCallQtMethodInDel(); + +private: + PythonQtTestCleanupHelper* _helper; +}; + +//! Test helper class +class PythonQtTestCleanupHelper : public QObject +{ + Q_OBJECT +public: + PythonQtTestCleanupHelper() : + _passed(false) { + }; + + bool runScript(const char* script); + +public Q_SLOTS: + void setPassed() { _passed = true; } + +private: + bool _passed; +}; + +#endif diff --git a/tests/PythonQtTestMain.cpp b/tests/PythonQtTestMain.cpp index 303ac0d0..ac3a37d8 100644 --- a/tests/PythonQtTestMain.cpp +++ b/tests/PythonQtTestMain.cpp @@ -41,6 +41,7 @@ #include "PythonQt.h" #include "PythonQtTests.h" +#include "PythonQtTestCleanup.h" #include @@ -60,6 +61,13 @@ int main(int argc, char *argv[]) PythonQt::cleanup(); + if (Py_IsInitialized()) { + Py_Finalize(); + } + + PythonQtTestCleanup cleanup; + failCount += QTest::qExec(&cleanup, argc, argv); + if (failCount>0) { std::cerr << "Tests failed: " << failCount << std::endl; } else { From af6cc5449a0770ecb698b26d3f448f8258d435f6 Mon Sep 17 00:00:00 2001 From: Max Smolens Date: Tue, 15 Sep 2015 15:45:30 -0400 Subject: [PATCH 25/28] Fix PythonQtSignalReceiver crash during cleanup This commit fixes a crash during PythonQt::cleanup(). While destroying the PythonQtPrivate instance, any remaining PythonQtSignalReceivers that are kept alive only by their parent object will be destroyed. The crash occurs when PythonQtSignalReceiver's destructor calls back into PythonQtPrivate::removeSignalEmitter() when the PythonQtPrivate instance is mostly destroyed. Includes test case that crashes without the fix. --- src/PythonQt.cpp | 4 ++++ tests/PythonQtTestCleanup.cpp | 21 ++++++++++++++++----- tests/PythonQtTestCleanup.h | 2 ++ 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/PythonQt.cpp b/src/PythonQt.cpp index d4443528..1ad6242f 100644 --- a/src/PythonQt.cpp +++ b/src/PythonQt.cpp @@ -246,6 +246,10 @@ void PythonQt::init(int flags, const QByteArray& pythonQtModuleName) void PythonQt::cleanup() { if (_self) { + // Remove signal handlers in advance, since destroying them calls back into + // PythonQt::priv()->removeSignalEmitter() + _self->removeSignalHandlers(); + delete _self; _self = NULL; } diff --git a/tests/PythonQtTestCleanup.cpp b/tests/PythonQtTestCleanup.cpp index 796c0eba..b60c7023 100644 --- a/tests/PythonQtTestCleanup.cpp +++ b/tests/PythonQtTestCleanup.cpp @@ -26,16 +26,14 @@ void PythonQtTestCleanup::cleanup() { // Finalize and cleanup after each test - PythonQtObjectPtr main = PythonQt::self()->getMainModule(); - PythonQt::self()->removeVariable(main, "obj"); - delete _helper; - _helper = NULL; - if (Py_IsInitialized()) { Py_Finalize(); } PythonQt::cleanup(); + + delete _helper; + _helper = NULL; } void PythonQtTestCleanup::testQtEnum() @@ -61,6 +59,19 @@ void PythonQtTestCleanup::testCallQtMethodInDel() )); } +void PythonQtTestCleanup::testSignalReceiverCleanup() +{ + PythonQtObjectPtr main = PythonQt::self()->getMainModule(); + + // Test that PythonQtSignalReceiver is cleaned up properly, + // i.e. PythonQt::cleanup() doesn't segfault + main.evalScript( + "import PythonQt.QtCore\n" \ + "timer = PythonQt.QtCore.QTimer(obj)\n" \ + "timer.connect('destroyed()', obj.onDestroyed)\n" \ + ); +} + bool PythonQtTestCleanupHelper::runScript(const char* script) { _passed = false; diff --git a/tests/PythonQtTestCleanup.h b/tests/PythonQtTestCleanup.h index 2c4879e2..b2a15886 100644 --- a/tests/PythonQtTestCleanup.h +++ b/tests/PythonQtTestCleanup.h @@ -19,6 +19,7 @@ private Q_SLOTS: void testQtEnum(); void testCallQtMethodInDel(); + void testSignalReceiverCleanup(); private: PythonQtTestCleanupHelper* _helper; @@ -37,6 +38,7 @@ class PythonQtTestCleanupHelper : public QObject public Q_SLOTS: void setPassed() { _passed = true; } + void onDestroyed(QObject *) { } private: bool _passed; From 0171dcef8a42dd59ee85e3ba5191c1b442ecd360 Mon Sep 17 00:00:00 2001 From: Eric Heim Date: Wed, 17 Feb 2016 15:19:40 +0100 Subject: [PATCH 26/28] Forked PythonQt 3.0 from Sourceforge and added CMake build system Conflicts: CMakeLists.txt --- CMakeLists.txt | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fdc15423..ee194473 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -352,18 +352,6 @@ if(BUILD_TESTING) ) endif() - if(PythonQt_Wrap_Qtcore) - include_directories(generated_cpp${generated_cpp_suffix}) - - list(APPEND test_sources - tests/PythonQtTestCleanup.cpp - tests/PythonQtTestCleanup.h - ) - QT4_WRAP_CPP(test_sources - tests/PythonQtTestCleanup.h - ) - endif() - set_property(SOURCE tests/PythonQtTestMain.cpp PROPERTY COMPILE_DEFINITIONS "main=tests_PythonQtTestMain") add_executable(PythonQtCppTests ${test_sources}) From 72abf215096bc0f843211bdb6e1bfbd15f594d56 Mon Sep 17 00:00:00 2001 From: Eric Heim Date: Mon, 11 May 2015 17:28:59 +0200 Subject: [PATCH 27/28] fixed rebase merge conflicts --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ee194473..4440f3e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -363,4 +363,3 @@ if(BUILD_TESTING) ) endif() - From 7bbf27f8034ddc03c9ddce33288ec310a0ec3a78 Mon Sep 17 00:00:00 2001 From: Eric Heim Date: Tue, 12 May 2015 09:57:34 +0200 Subject: [PATCH 28/28] fixed win32 linker issues and test build with qt5 --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4440f3e2..ee194473 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -363,3 +363,4 @@ if(BUILD_TESTING) ) endif() +