From cee71e1fb1c276564de327d2eb7d89181da40fbd Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 7 Mar 2026 15:12:57 -0600 Subject: [PATCH] CMake: Add check for Qt/PySide version mismatch (#27156) * CMake: fixes issue #27065 check for Qt/PySide version mismatches * lint / format several PySide related CMake files --- cMake/FindPySide6.cmake | 50 +++++++++++++++---- cMake/FindPySide6Tools.cmake | 12 ++--- cMake/FindShiboken6.cmake | 4 +- .../SetupShibokenAndPyside.cmake | 40 +++++++-------- 4 files changed, 69 insertions(+), 37 deletions(-) diff --git a/cMake/FindPySide6.cmake b/cMake/FindPySide6.cmake index 4ddb5b179f..59e30e64db 100644 --- a/cMake/FindPySide6.cmake +++ b/cMake/FindPySide6.cmake @@ -1,7 +1,11 @@ -# The Qt for Python project officially recommends using pip to install PySide, so we expect to find PySide in the -# site-packages directory. The library will be called "PySide6.abi3.*", and there will be an "include" directory inside -# the site-packages/PySide6. Over time some distros may provide custom versions, so we also support using a more normal -# cMake find_package() call +# The Qt for Python project officially recommends using pip to install PySide, +# so we expect to find PySide in the site-packages directory. +# The library will be called "PySide6.abi3.*", and there will +# be an "include" directory inside the site-packages/PySide6. +# Over time some distros may provide custom versions, so we also support +# using a more normal cMake find_package() call + +include(FindPackageHandleStandardArgs) find_package(PySide6 CONFIG QUIET) @@ -9,12 +13,40 @@ if(NOT PySide6_FOUND) find_pip_package(PySide6) endif() -if(NOT PySide6_INCLUDE_DIRS AND TARGET PySide6::pyside6) - get_property(PySide6_INCLUDE_DIRS TARGET PySide6::pyside6 PROPERTY INTERFACE_INCLUDE_DIRECTORIES) -endif() +if(PySide6_FOUND) + # verify PySide6 version matches Qt6 version (major.minor) + if(PySide6_VERSION AND Qt6_VERSION) + string(REGEX MATCH "^([0-9]+)\\.([0-9]+)" _qt6_major_minor "${Qt6_VERSION}") + string(REGEX MATCH "^([0-9]+)\\.([0-9]+)" _pyside6_major_minor "${PySide6_VERSION}") -# Also provide the old-style variables so we don't have to update everything yet -if (PySide6_FOUND) + message(STATUS "Qt version: ${Qt6_VERSION}") + message(STATUS "PySide version: ${PySide6_VERSION}") + + if(NOT _qt6_major_minor STREQUAL _pyside6_major_minor) + message(FATAL_ERROR +" -------------------------------------------------------- + Qt/PySide version mismatch! + cmake found Qt: ${Qt6_VERSION} + cmake found PySide: ${PySide6_VERSION} + major.minor versions of Qt and PySide must match to avoid errors. + Ensure CMAKE_PREFIX_PATH points to matching Qt and PySide6 installations. + --------------------------------------------------------" + ) + endif() + + message(STATUS "PySide/Qt version check passed (${_pyside6_major_minor})") + endif() + + if(NOT PySide6_INCLUDE_DIRS AND TARGET PySide6::pyside6) + get_property(PySide6_INCLUDE_DIRS TARGET PySide6::pyside6 PROPERTY INTERFACE_INCLUDE_DIRECTORIES) + endif() + + find_package_handle_standard_args(PySide6 + REQUIRED_VARS PySide6_INCLUDE_DIRS + VERSION_VAR PySide6_VERSION + ) + + # Also provide the old-style variables so we don't have to update everything yet set(PYSIDE_INCLUDE_DIR ${PySide6_INCLUDE_DIRS}) set(PYSIDE_LIBRARY ${PySide6_LIBRARIES}) set(PYSIDE_FOUND TRUE) diff --git a/cMake/FindPySide6Tools.cmake b/cMake/FindPySide6Tools.cmake index 2c4b8c02b6..f8184705f1 100644 --- a/cMake/FindPySide6Tools.cmake +++ b/cMake/FindPySide6Tools.cmake @@ -3,11 +3,11 @@ # PYSIDE_RCC_EXECUTABLE - Location of PYSIDE6RCC executable # PYSIDE_TOOLS_FOUND - PYSIDE6 utilities found. -if (TARGET Qt6::uic) +if(TARGET Qt6::uic) get_target_property(PYSIDE6_UIC_EXECUTABLE Qt6::uic LOCATION) set(UICOPTIONS "--generator=python") endif() -if (TARGET Qt6::rcc) +if(TARGET Qt6::rcc) get_target_property(PYSIDE6_RCC_EXECUTABLE Qt6::rcc LOCATION) set(RCCOPTIONS "--generator=python" "--compress-algo=zlib" "--compress=1") endif() @@ -18,15 +18,15 @@ set(PySideTools_VERSION 6) if(PYSIDE_RCC_EXECUTABLE AND PYSIDE_UIC_EXECUTABLE) set(PYSIDE_TOOLS_FOUND TRUE) - if (NOT PYSIDE6Tools_FIND_QUIETLY) + if(NOT PYSIDE6Tools_FIND_QUIETLY) message(STATUS "Found PYSIDE6 tools: ${PYSIDE_UIC_EXECUTABLE}, ${PYSIDE_RCC_EXECUTABLE}") - endif () + endif() else() if(PYSIDE6Tools_FIND_REQUIRED) message(FATAL_ERROR "PYSIDE6 tools could not be found, but are required.") else() - if (NOT PYSIDE6Tools_FIND_QUIETLY) + if(NOT PYSIDE6Tools_FIND_QUIETLY) message(STATUS "PYSIDE6 tools: not found.") - endif () + endif() endif() endif() diff --git a/cMake/FindShiboken6.cmake b/cMake/FindShiboken6.cmake index c32b55901e..2200840ed6 100644 --- a/cMake/FindShiboken6.cmake +++ b/cMake/FindShiboken6.cmake @@ -10,14 +10,14 @@ if(NOT Shiboken6_FOUND) endif() if(NOT Shiboken6_INCLUDE_DIR) find_pip_package(Shiboken6) - if (Shiboken6_FOUND) + if(Shiboken6_FOUND) set(SHIBOKEN_LIBRARY ${Shiboken6_LIBRARIES}) set(SHIBOKEN_MAJOR_VERSION 6) set(SHIBOKEN_FOUND ON) endif() # The include directory we actually want is part of shiboken6-generator find_pip_package(shiboken6_generator) - if (shiboken6_generator_FOUND) + if(shiboken6_generator_FOUND) set(SHIBOKEN_INCLUDE_DIR ${shiboken6_generator_INCLUDE_DIRS}) endif() endif() diff --git a/cMake/FreeCAD_Helpers/SetupShibokenAndPyside.cmake b/cMake/FreeCAD_Helpers/SetupShibokenAndPyside.cmake index 93c28876b8..a9839821ca 100644 --- a/cMake/FreeCAD_Helpers/SetupShibokenAndPyside.cmake +++ b/cMake/FreeCAD_Helpers/SetupShibokenAndPyside.cmake @@ -7,7 +7,7 @@ macro(SetupShibokenAndPyside) if(DEFINED MACPORTS_PREFIX) find_package(Shiboken REQUIRED HINTS "${PYTHON_LIBRARY_DIR}/cmake") find_package(PySide REQUIRED HINTS "${PYTHON_LIBRARY_DIR}/cmake") - endif(DEFINED MACPORTS_PREFIX) + endif() if(FREECAD_QT_MAJOR_VERSION EQUAL 5) set(SHIBOKEN_MAJOR_VERSION 2) @@ -21,16 +21,16 @@ macro(SetupShibokenAndPyside) # Shiboken2Config.cmake may explicitly set CMAKE_BUILD_TYPE to Release which causes # CMake to fail to create Makefiles for a debug build. # So as a workaround we save and restore the value after checking for Shiboken2. - set (SAVE_BUILD_TYPE ${CMAKE_BUILD_TYPE}) + set(SAVE_BUILD_TYPE ${CMAKE_BUILD_TYPE}) find_package(Shiboken${SHIBOKEN_MAJOR_VERSION} QUIET) - set (CMAKE_BUILD_TYPE ${SAVE_BUILD_TYPE}) - if (Shiboken${SHIBOKEN_MAJOR_VERSION}_FOUND) + set(CMAKE_BUILD_TYPE ${SAVE_BUILD_TYPE}) + if(Shiboken${SHIBOKEN_MAJOR_VERSION}_FOUND) # Shiboken config file was found but it may use the wrong Python version # Try to get the matching config suffix and repeat finding the package set(SHIBOKEN_PATTERN .cpython-${Python3_VERSION_MAJOR}${Python3_VERSION_MINOR}) file(GLOB SHIBOKEN_CONFIG "${Shiboken${SHIBOKEN_MAJOR_VERSION}_DIR}/Shiboken${SHIBOKEN_MAJOR_VERSION}Config${SHIBOKEN_PATTERN}*.cmake") - if (SHIBOKEN_CONFIG) + if(SHIBOKEN_CONFIG) get_filename_component(SHIBOKEN_CONFIG_SUFFIX ${SHIBOKEN_CONFIG} NAME) string(SUBSTRING ${SHIBOKEN_CONFIG_SUFFIX} 15 -1 SHIBOKEN_CONFIG_SUFFIX) string(REPLACE ".cmake" "" PYTHON_CONFIG_SUFFIX ${SHIBOKEN_CONFIG_SUFFIX}) @@ -47,11 +47,11 @@ macro(SetupShibokenAndPyside) # to dance to be compatible with the old (<5.12) and the new versions (>=5.12) if(NOT SHIBOKEN_INCLUDE_DIR AND TARGET Shiboken${SHIBOKEN_MAJOR_VERSION}::libshiboken) get_property(SHIBOKEN_INCLUDE_DIR TARGET Shiboken${SHIBOKEN_MAJOR_VERSION}::libshiboken PROPERTY INTERFACE_INCLUDE_DIRECTORIES) - endif(NOT SHIBOKEN_INCLUDE_DIR AND TARGET Shiboken${SHIBOKEN_MAJOR_VERSION}::libshiboken) + endif() if(NOT SHIBOKEN_INCLUDE_DIR) find_pip_package(Shiboken${SHIBOKEN_MAJOR_VERSION}) - if (Shiboken${SHIBOKEN_MAJOR_VERSION}_FOUND) + if(Shiboken${SHIBOKEN_MAJOR_VERSION}_FOUND) set(SHIBOKEN_INCLUDE_DIR ${Shiboken${SHIBOKEN_MAJOR_VERSION}_INCLUDE_DIRS}) set(SHIBOKEN_LIBRARY ${Shiboken${SHIBOKEN_MAJOR_VERSION}_LIBRARIES}) endif() @@ -63,11 +63,11 @@ macro(SetupShibokenAndPyside) # Our internal FindPySide6.cmake file already provides these for PySide6 if(NOT PYSIDE_INCLUDE_DIR AND TARGET PySide${PYSIDE_MAJOR_VERSION}::pyside${PYSIDE_MAJOR_VERSION}) get_property(PYSIDE_INCLUDE_DIR TARGET PySide${PYSIDE_MAJOR_VERSION}::pyside${PYSIDE_MAJOR_VERSION} PROPERTY INTERFACE_INCLUDE_DIRECTORIES) - endif(NOT PYSIDE_INCLUDE_DIR AND TARGET PySide${PYSIDE_MAJOR_VERSION}::pyside${PYSIDE_MAJOR_VERSION}) + endif() if(NOT PYSIDE_INCLUDE_DIR) find_pip_package(PySide${PYSIDE_MAJOR_VERSION}) - if (PySide${PYSIDE_MAJOR_VERSION}_FOUND) + if(PySide${PYSIDE_MAJOR_VERSION}_FOUND) set(PYSIDE_INCLUDE_DIR ${PySide${PYSIDE_MAJOR_VERSION}_INCLUDE_DIRS}) set(PYSIDE_LIBRARY ${PySide${PYSIDE_MAJOR_VERSION}_LIBRARIES}) endif() @@ -175,22 +175,22 @@ macro(SetupShibokenAndPyside) message(STATUS "PySide ${PySide_VERSION} Python module found at ${PRINT_OUTPUT}.\n") endif() -endmacro(SetupShibokenAndPyside) +endmacro() -MACRO(PYSIDE_WRAP_RC outfiles) - if (NOT PYSIDE_RCC_EXECUTABLE) +macro(PYSIDE_WRAP_RC outfiles) + if(NOT PYSIDE_RCC_EXECUTABLE) message(FATAL_ERROR "Qt rcc is required for generating ${ARGN}") endif() - FOREACH(it ${ARGN}) - GET_FILENAME_COMPONENT(outfile ${it} NAME_WE) - GET_FILENAME_COMPONENT(infile ${it} ABSOLUTE) - SET(outfile "${CMAKE_CURRENT_BINARY_DIR}/${outfile}_rc.py") + foreach(it ${ARGN}) + get_filename_component(outfile ${it} NAME_WE) + get_filename_component(infile ${it} ABSOLUTE) + set(outfile "${CMAKE_CURRENT_BINARY_DIR}/${outfile}_rc.py") #ADD_CUSTOM_TARGET(${it} ALL # DEPENDS ${outfile} #) if(WIN32 OR APPLE) - ADD_CUSTOM_COMMAND(OUTPUT ${outfile} + add_custom_command(OUTPUT ${outfile} COMMAND ${PYSIDE_RCC_EXECUTABLE} ${RCCOPTIONS} ${infile} -o ${outfile} MAIN_DEPENDENCY ${infile} ) @@ -198,7 +198,7 @@ MACRO(PYSIDE_WRAP_RC outfiles) # Especially on Open Build Service we don't want changing date like # pyside-rcc generates in comments at beginning, which is why # we follow the tool command with in-place sed. - ADD_CUSTOM_COMMAND(OUTPUT "${outfile}" + add_custom_command(OUTPUT "${outfile}" COMMAND "${PYSIDE_RCC_EXECUTABLE}" ${RCCOPTIONS} "${infile}" ${PY_ATTRIBUTE} -o "${outfile}" # The line below sometimes catches unwanted lines too - but there is no date in the file # anymore with Qt5 RCC, so commenting it out for now... @@ -207,5 +207,5 @@ MACRO(PYSIDE_WRAP_RC outfiles) ) endif() list(APPEND ${outfiles} ${outfile}) - ENDFOREACH(it) -ENDMACRO (PYSIDE_WRAP_RC) + endforeach() +endmacro()