Skip to content

Commit c5bb41d

Browse files
committedSep 30, 2021
PyQt5 cmake improvements
1 parent e6d3480 commit c5bb41d

File tree

6 files changed

+105
-92
lines changed

6 files changed

+105
-92
lines changed
 

‎CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -929,12 +929,12 @@ if (WITH_CORE AND WITH_BINDINGS AND NOT WITH_QT6)
929929
set (QGIS_PYTHON_OUTPUT_DIRECTORY ${PYTHON_OUTPUT_DIRECTORY}/qgis)
930930

931931
# python support: check for interpreter, sip, pyqt5
932+
find_package(SIP REQUIRED)
932933
find_package(PyQt5 REQUIRED)
933934
set(PYQT_SIP_FLAGS ${PYQT5_SIP_FLAGS})
934935
set(PYQT_SIP_DIR ${PYQT5_SIP_DIR})
935936
separate_arguments(PYQT_SIP_FLAGS) # convert space separated values to a list
936937

937-
find_package(SIP REQUIRED)
938938
find_package(Qsci REQUIRED)
939939
include(PythonMacros)
940940
include(PyQtMacros)

‎cmake/FindPyQt5.cmake

Lines changed: 45 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,40 +11,58 @@
1111
#
1212
# This file defines the following variables:
1313
#
14-
# PYQT5_VERSION - The version of PyQt5 found expressed as a 6 digit hex number
15-
# suitable for comparison as a string
16-
#
1714
# PYQT5_VERSION_STR - The version of PyQt5 as a human readable string.
1815
#
19-
# PYQT5_VERSION_TAG - The PyQt version tag using by PyQt's sip files.
20-
#
2116
# PYQT5_SIP_DIR - The directory holding the PyQt5 .sip files.
2217
#
2318
# PYQT5_SIP_FLAGS - The SIP flags used to build PyQt.
2419

25-
IF(EXISTS PYQT5_VERSION)
20+
IF(EXISTS PYQT5_VERSION_STR)
2621
# Already in cache, be silent
2722
SET(PYQT5_FOUND TRUE)
28-
ELSE(EXISTS PYQT5_VERSION)
29-
30-
FIND_FILE(_find_pyqt5_py FindPyQt5.py PATHS ${CMAKE_MODULE_PATH} NO_CMAKE_FIND_ROOT_PATH)
31-
32-
EXECUTE_PROCESS(COMMAND ${Python_EXECUTABLE} ${_find_pyqt5_py} OUTPUT_VARIABLE pyqt_config)
33-
IF(pyqt_config)
34-
STRING(REGEX REPLACE "^pyqt_version:([^\n]+).*$" "\\1" PYQT5_VERSION ${pyqt_config})
35-
STRING(REGEX REPLACE ".*\npyqt_version_str:([^\n]+).*$" "\\1" PYQT5_VERSION_STR ${pyqt_config})
36-
STRING(REGEX REPLACE ".*\npyqt_version_tag:([^\n]+).*$" "\\1" PYQT5_VERSION_TAG ${pyqt_config})
37-
STRING(REGEX REPLACE ".*\npyqt_version_num:([^\n]+).*$" "\\1" PYQT5_VERSION_NUM ${pyqt_config})
38-
STRING(REGEX REPLACE ".*\npyqt_mod_dir:([^\n]+).*$" "\\1" PYQT5_MOD_DIR ${pyqt_config})
39-
STRING(REGEX REPLACE ".*\npyqt_sip_dir:([^\n]+).*$" "\\1" PYQT5_SIP_DIR ${pyqt_config})
40-
IF(EXISTS ${PYQT5_SIP_DIR}/Qt5)
41-
SET(PYQT5_SIP_DIR ${PYQT5_SIP_DIR}/Qt5)
42-
ENDIF(EXISTS ${PYQT5_SIP_DIR}/Qt5)
43-
STRING(REGEX REPLACE ".*\npyqt_sip_flags:([^\n]+).*$" "\\1" PYQT5_SIP_FLAGS ${pyqt_config})
44-
STRING(REGEX REPLACE ".*\npyqt_bin_dir:([^\n]+).*$" "\\1" PYQT5_BIN_DIR ${pyqt_config})
45-
STRING(REGEX REPLACE ".*\npyqt_sip_module:([^\n]+).*$" "\\1" PYQT5_SIP_IMPORT ${pyqt_config})
46-
SET(PYQT5_FOUND TRUE)
47-
ENDIF(pyqt_config)
23+
ELSE(EXISTS PYQT5_VERSION_STR)
24+
25+
IF(SIP_BUILD_EXECUTABLE)
26+
# SIP >= 5.0 path
27+
28+
29+
FILE(GLOB _pyqt5_metadata "${Python_SITEARCH}/PyQt5*.dist-info/METADATA")
30+
IF(_pyqt5_metadata)
31+
FILE(READ ${_pyqt5_metadata} _pyqt5_metadata_contents)
32+
STRING(REGEX REPLACE ".*\nVersion: ([^\n]+).*$" "\\1" PYQT5_VERSION_STR ${_pyqt5_metadata_contents})
33+
ELSE(_pyqt5_metadata)
34+
EXECUTE_PROCESS(COMMAND ${Python_EXECUTABLE} -c "from PyQt5.QtCore import PYQT_VERSION_STR; print(PYQT_VERSION_STR)" OUTPUT_VARIABLE PYQT5_VERSION_STR)
35+
ENDIF(_pyqt5_metadata)
36+
37+
IF(PYQT5_VERSION_STR)
38+
SET(PYQT5_MOD_DIR "${Python_SITEARCH}/PyQt5")
39+
SET(PYQT5_SIP_DIR "${Python_SITEARCH}/PyQt5/bindings")
40+
FIND_PROGRAM(__pyuic5 "pyuic5")
41+
GET_FILENAME_COMPONENT(PYQT5_BIN_DIR ${__pyuic5} DIRECTORY)
42+
43+
SET(PYQT5_FOUND TRUE)
44+
ENDIF(PYQT5_VERSION_STR)
45+
46+
ELSE(SIP_BUILD_EXECUTABLE)
47+
# SIP 4.x path
48+
49+
FIND_FILE(_find_pyqt5_py FindPyQt5.py PATHS ${CMAKE_MODULE_PATH} NO_CMAKE_FIND_ROOT_PATH)
50+
51+
EXECUTE_PROCESS(COMMAND ${Python_EXECUTABLE} ${_find_pyqt5_py} OUTPUT_VARIABLE pyqt_config)
52+
IF(pyqt_config)
53+
STRING(REGEX REPLACE "^pyqt_version_str:([^\n]+).*$" "\\1" PYQT5_VERSION_STR ${pyqt_config})
54+
STRING(REGEX REPLACE ".*\npyqt_mod_dir:([^\n]+).*$" "\\1" PYQT5_MOD_DIR ${pyqt_config})
55+
STRING(REGEX REPLACE ".*\npyqt_sip_dir:([^\n]+).*$" "\\1" PYQT5_SIP_DIR ${pyqt_config})
56+
IF(EXISTS ${PYQT5_SIP_DIR}/Qt5)
57+
SET(PYQT5_SIP_DIR ${PYQT5_SIP_DIR}/Qt5)
58+
ENDIF(EXISTS ${PYQT5_SIP_DIR}/Qt5)
59+
STRING(REGEX REPLACE ".*\npyqt_sip_flags:([^\n]+).*$" "\\1" PYQT5_SIP_FLAGS ${pyqt_config})
60+
STRING(REGEX REPLACE ".*\npyqt_bin_dir:([^\n]+).*$" "\\1" PYQT5_BIN_DIR ${pyqt_config})
61+
STRING(REGEX REPLACE ".*\npyqt_sip_module:([^\n]+).*$" "\\1" PYQT5_SIP_IMPORT ${pyqt_config})
62+
SET(PYQT5_FOUND TRUE)
63+
ENDIF(pyqt_config)
64+
65+
ENDIF(SIP_BUILD_EXECUTABLE)
4866

4967
IF(PYQT5_FOUND)
5068
IF(NOT PyQt5_FIND_QUIETLY)
@@ -56,4 +74,4 @@ ELSE(EXISTS PYQT5_VERSION)
5674
ENDIF(PyQt5_FIND_REQUIRED)
5775
ENDIF(PYQT5_FOUND)
5876

59-
ENDIF(EXISTS PYQT5_VERSION)
77+
ENDIF(EXISTS PYQT5_VERSION_STR)

‎cmake/FindPyQt5.py

Lines changed: 15 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -32,57 +32,24 @@
3232

3333
import os.path
3434
import PyQt5.QtCore
35+
import sipconfig
36+
import sys
37+
38+
cfg = sipconfig.Configuration()
39+
sip_dir = cfg.default_sip_dir
40+
for p in (os.path.join(sip_dir, "PyQt5"),
41+
os.path.join(sip_dir, "PyQt5-3"),
42+
sip_dir,
43+
os.path.join(cfg.default_mod_dir, "PyQt5", "bindings")):
44+
if os.path.exists(os.path.join(p, "QtCore", "QtCoremod.sip")):
45+
sip_dir = p
46+
break
3547

36-
try:
37-
__import__('sipbuild')
38-
except ImportError:
39-
import sipconfig # won't work for SIP v5
40-
import sys
41-
42-
cfg = sipconfig.Configuration()
43-
sip_dir = cfg.default_sip_dir
44-
for p in (os.path.join(sip_dir, "PyQt5"),
45-
os.path.join(sip_dir, "PyQt5-3"),
46-
sip_dir,
47-
os.path.join(cfg.default_mod_dir, "PyQt5", "bindings")):
48-
if os.path.exists(os.path.join(p, "QtCore", "QtCoremod.sip")):
49-
sip_dir = p
50-
break
51-
cfg = {
52-
'pyqt_mod_dir': os.path.join(cfg.default_mod_dir, "PyQt5"),
53-
'pyqt_sip_dir': sip_dir,
54-
'pyqt_bin_dir': cfg.default_bin_dir,
55-
}
56-
else: # Code for SIP v5
57-
from distutils.sysconfig import get_python_lib
58-
import shutil
59-
cfg = {
60-
'pyqt_mod_dir': os.path.dirname(PyQt5.__file__),
61-
'pyqt_sip_dir': os.path.join(get_python_lib(plat_specific=1), "PyQt5", "bindings"),
62-
'pyqt_bin_dir': os.path.dirname(shutil.which("pyuic5")),
63-
}
64-
65-
print("pyqt_version:%06.0x" % PyQt5.QtCore.PYQT_VERSION)
66-
print("pyqt_version_num:%d" % PyQt5.QtCore.PYQT_VERSION)
6748
print("pyqt_version_str:%s" % PyQt5.QtCore.PYQT_VERSION_STR)
68-
69-
pyqt_version_tag = ""
70-
in_t = False
71-
pyqt_config_list = PyQt5.QtCore.PYQT_CONFIGURATION["sip_flags"].split(' ')
72-
for item in pyqt_config_list:
73-
if item == "-t":
74-
in_t = True
75-
elif in_t:
76-
if item.startswith("Qt_5"):
77-
pyqt_version_tag = item
78-
else:
79-
in_t = False
80-
print("pyqt_version_tag:%s" % pyqt_version_tag)
81-
82-
print("pyqt_mod_dir:%s" % cfg['pyqt_mod_dir'])
83-
print("pyqt_sip_dir:%s" % cfg['pyqt_sip_dir'])
49+
print("pyqt_mod_dir:%s" % os.path.join(cfg.default_mod_dir, "PyQt5"))
50+
print("pyqt_sip_dir:%s" % sip_dir)
8451
print("pyqt_sip_flags:%s" % PyQt5.QtCore.PYQT_CONFIGURATION['sip_flags'])
85-
print("pyqt_bin_dir:%s" % cfg['pyqt_bin_dir'])
52+
print("pyqt_bin_dir:%s" % cfg.default_bin_dir)
8653

8754
try:
8855
import PyQt5.sip

‎cmake/FindQsci.cmake

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,23 +21,43 @@ IF(QSCI_MOD_VERSION_STR)
2121
SET(QSCI_FOUND TRUE)
2222
ELSE(QSCI_MOD_VERSION_STR)
2323

24-
FIND_FILE(_find_qsci_py FindQsci.py PATHS ${CMAKE_MODULE_PATH} NO_CMAKE_FIND_ROOT_PATH)
24+
IF(SIP_BUILD_EXECUTABLE)
25+
# SIP >= 5.0 path
2526

26-
SET(QSCI_VER 5)
27+
FILE(GLOB _qsci_metadata "${Python_SITEARCH}/QScintilla*.dist-info/METADATA")
28+
IF(_qsci_metadata)
29+
FILE(READ ${_qsci_metadata} _qsci_metadata_contents)
30+
STRING(REGEX REPLACE ".*\nVersion: ([^\n]+).*$" "\\1" QSCI_MOD_VERSION_STR ${_qsci_metadata_contents})
31+
ELSE(_qsci_metadata)
32+
EXECUTE_PROCESS(COMMAND ${Python_EXECUTABLE} -c "from PyQt5.Qsci import QSCINTILLA_VERSION_STR; print(QSCINTILLA_VERSION_STR)" OUTPUT_VARIABLE QSCI_MOD_VERSION_STR)
33+
ENDIF(_qsci_metadata)
2734

28-
EXECUTE_PROCESS(COMMAND ${Python_EXECUTABLE} ${_find_qsci_py} ${QSCI_VER} OUTPUT_VARIABLE qsci_ver)
35+
IF(QSCI_MOD_VERSION_STR)
36+
SET(QSCI_SIP_DIR "${PYQT5_SIP_DIR}")
37+
SET(QSCI_FOUND TRUE)
38+
ENDIF(QSCI_MOD_VERSION_STR)
2939

30-
IF(qsci_ver)
31-
STRING(REGEX REPLACE "^qsci_version_str:([^\n]+).*$" "\\1" QSCI_MOD_VERSION_STR ${qsci_ver})
32-
SET(QSCI_FOUND TRUE)
33-
ENDIF(qsci_ver)
40+
ELSE(SIP_BUILD_EXECUTABLE)
41+
# SIP 4.x path
3442

35-
IF(QSCI_FOUND)
36-
FIND_PATH(QSCI_SIP_DIR
37-
NAMES Qsci/qscimod5.sip
38-
PATHS ${PYQT5_SIP_DIR} ${SIP_DEFAULT_SIP_DIR}
39-
)
43+
FIND_FILE(_find_qsci_py FindQsci.py PATHS ${CMAKE_MODULE_PATH} NO_CMAKE_FIND_ROOT_PATH)
44+
45+
SET(QSCI_VER 5)
46+
47+
EXECUTE_PROCESS(COMMAND ${Python_EXECUTABLE} ${_find_qsci_py} ${QSCI_VER} OUTPUT_VARIABLE qsci_ver)
4048

49+
IF(qsci_ver)
50+
STRING(REGEX REPLACE "^qsci_version_str:([^\n]+).*$" "\\1" QSCI_MOD_VERSION_STR ${qsci_ver})
51+
FIND_PATH(QSCI_SIP_DIR
52+
NAMES Qsci/qscimod5.sip
53+
PATHS ${PYQT5_SIP_DIR} ${SIP_DEFAULT_SIP_DIR}
54+
)
55+
SET(QSCI_FOUND TRUE)
56+
ENDIF(qsci_ver)
57+
58+
ENDIF(SIP_BUILD_EXECUTABLE)
59+
60+
IF(QSCI_FOUND)
4161
IF(NOT QSCI_FIND_QUIETLY)
4262
MESSAGE(STATUS "Found QScintilla2 PyQt module: ${QSCI_MOD_VERSION_STR}")
4363
ENDIF(NOT QSCI_FIND_QUIETLY)

‎cmake/PyQtMacros.cmake

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ ENDIF(NOT PYUIC_PROGRAM)
1717

1818
# Adapted from QT4_WRAP_UI
1919
MACRO(PYQT_WRAP_UI outfiles )
20+
SET(PYUIC_WRAPPER_OUTPUT_DIRECTORY "${PYTHON_OUTPUT_DIRECTORY}")
21+
SET(PYUIC_WRAPPER_PYTHON_EXECUTABLE "${Python_EXECUTABLE}")
2022
IF(CMAKE_HOST_WIN32)
2123
IF(USING_NINJA OR USING_NMAKE)
2224
SET(PYUIC_WRAPPER "${CMAKE_SOURCE_DIR}/scripts/pyuic_wrapper.bat")
@@ -25,18 +27,22 @@ MACRO(PYQT_WRAP_UI outfiles )
2527
SET(PYUIC_WRAPPER "${CMAKE_SOURCE_DIR}/scripts/pyuic_wrapper.bat")
2628
SET(PYUIC_WRAPPER_PATH "${QGIS_OUTPUT_DIRECTORY}/bin/${CMAKE_BUILD_TYPE}")
2729
ENDIF(USING_NINJA OR USING_NMAKE)
28-
ELSE(CMAKE_HOST_WIN32)
30+
ELSEIF(MINGW)
31+
# Clear all variables to invoke PYUIC_PROGRAM directly
32+
SET(PYUIC_WRAPPER_OUTPUT_DIRECTORY "")
33+
SET(PYUIC_WRAPPER_PYTHON_EXECUTABLE "")
34+
ELSE()
2935
# TODO osx
3036
SET(PYUIC_WRAPPER "${CMAKE_SOURCE_DIR}/scripts/pyuic_wrapper.sh")
3137
SET(PYUIC_WRAPPER_PATH "${QGIS_OUTPUT_DIRECTORY}/lib")
32-
ENDIF(CMAKE_HOST_WIN32)
38+
ENDIF()
3339

3440
FOREACH(it ${ARGN})
3541
GET_FILENAME_COMPONENT(outfile ${it} NAME_WE)
3642
GET_FILENAME_COMPONENT(infile ${it} ABSOLUTE)
3743
SET(outfile ${CMAKE_CURRENT_BINARY_DIR}/ui_${outfile}.py)
3844
ADD_CUSTOM_COMMAND(OUTPUT ${outfile}
39-
COMMAND ${PYUIC_WRAPPER} "${PYUIC_PROGRAM}" "${PYUIC_WRAPPER_PATH}" "${PYTHON_OUTPUT_DIRECTORY}" "${Python_EXECUTABLE}" ${infile} -o ${outfile}
45+
COMMAND ${PYUIC_WRAPPER} "${PYUIC_PROGRAM}" "${PYUIC_WRAPPER_PATH}" "${PYUIC_WRAPPER_OUTPUT_DIRECTORY}" "${PYUIC_WRAPPER_PYTHON_EXECUTABLE}" ${infile} -o ${outfile}
4046
MAIN_DEPENDENCY ${infile}
4147
DEPENDS pygui pycore pyqtcompat
4248
)

‎python/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,11 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
167167
add_definitions(-std=c++14)
168168
endif()
169169

170-
if(UNIX AND NOT SIP_VERSION_NUM LESS 265984)
170+
if((UNIX OR MINGW) AND SIP_VERSION_STR VERSION_GREATER_EQUAL 4.10 AND SIP_VERSION_STR VERSION_LESS 5.0)
171171
set(SIP_EXTRA_OPTIONS -P ${SIP_EXTRA_OPTIONS})
172172
add_definitions(-Dprotected=public)
173+
elseif((UNIX OR MINGW) AND SIP_VERSION_STR VERSION_GREATER_EQUAL 5.0)
174+
add_definitions(-Dprotected=public)
173175
endif()
174176

175177
set (PY_MODULES core)

0 commit comments

Comments
 (0)