FreeCAD
268 строк · 12.5 Кб
1macro(SetupShibokenAndPyside)
2# -------------------------------- Shiboken/PySide ------------------------
3
4option(FREECAD_USE_SHIBOKEN "Links to the shiboken library at build time. If OFF its Python module is imported at runtime" ON)
5option(FREECAD_USE_PYSIDE "Links to the PySide libraries at build time." ON)
6
7if(DEFINED MACPORTS_PREFIX)
8find_package(Shiboken REQUIRED HINTS "${PYTHON_LIBRARY_DIR}/cmake")
9find_package(PySide REQUIRED HINTS "${PYTHON_LIBRARY_DIR}/cmake")
10endif(DEFINED MACPORTS_PREFIX)
11
12if(FREECAD_QT_MAJOR_VERSION EQUAL 5)
13set(SHIBOKEN_MAJOR_VERSION 2)
14set(PYSIDE_MAJOR_VERSION 2)
15else()
16set(SHIBOKEN_MAJOR_VERSION ${FREECAD_QT_MAJOR_VERSION})
17set(PYSIDE_MAJOR_VERSION ${FREECAD_QT_MAJOR_VERSION})
18endif()
19
20
21# Shiboken2Config.cmake may explicitly set CMAKE_BUILD_TYPE to Release which causes
22# CMake to fail to create Makefiles for a debug build.
23# So as a workaround we save and restore the value after checking for Shiboken2.
24set (SAVE_BUILD_TYPE ${CMAKE_BUILD_TYPE})
25find_package(Shiboken${SHIBOKEN_MAJOR_VERSION} QUIET)
26set (CMAKE_BUILD_TYPE ${SAVE_BUILD_TYPE})
27if (Shiboken${SHIBOKEN_MAJOR_VERSION}_FOUND)
28# Shiboken config file was found but it may use the wrong Python version
29# Try to get the matching config suffix and repeat finding the package
30set(SHIBOKEN_PATTERN .cpython-${Python3_VERSION_MAJOR}${Python3_VERSION_MINOR})
31
32file(GLOB SHIBOKEN_CONFIG "${Shiboken${SHIBOKEN_MAJOR_VERSION}_DIR}/Shiboken${SHIBOKEN_MAJOR_VERSION}Config${SHIBOKEN_PATTERN}*.cmake")
33if (SHIBOKEN_CONFIG)
34get_filename_component(SHIBOKEN_CONFIG_SUFFIX ${SHIBOKEN_CONFIG} NAME)
35string(SUBSTRING ${SHIBOKEN_CONFIG_SUFFIX} 15 -1 SHIBOKEN_CONFIG_SUFFIX)
36string(REPLACE ".cmake" "" PYTHON_CONFIG_SUFFIX ${SHIBOKEN_CONFIG_SUFFIX})
37message(STATUS "PYTHON_CONFIG_SUFFIX: ${PYTHON_CONFIG_SUFFIX}")
38find_package(Shiboken${SHIBOKEN_MAJOR_VERSION} QUIET)
39endif()
40endif()
41
42# pyside2 changed its cmake files, this is the dance we have
43# to dance to be compatible with the old (<5.12) and the new versions (>=5.12)
44if(NOT SHIBOKEN_INCLUDE_DIR AND TARGET Shiboken${SHIBOKEN_MAJOR_VERSION}::libshiboken)
45get_property(SHIBOKEN_INCLUDE_DIR TARGET Shiboken${SHIBOKEN_MAJOR_VERSION}::libshiboken PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
46endif(NOT SHIBOKEN_INCLUDE_DIR AND TARGET Shiboken${SHIBOKEN_MAJOR_VERSION}::libshiboken)
47
48if(NOT SHIBOKEN_INCLUDE_DIR)
49find_pip_package(Shiboken${SHIBOKEN_MAJOR_VERSION})
50if (Shiboken${SHIBOKEN_MAJOR_VERSION}_FOUND)
51set(SHIBOKEN_INCLUDE_DIR ${Shiboken${SHIBOKEN_MAJOR_VERSION}_INCLUDE_DIR})
52set(SHIBOKEN_LIBRARY ${Shiboken${SHIBOKEN_MAJOR_VERSION}_LIBRARY})
53endif()
54endif()
55
56find_package(PySide${PYSIDE_MAJOR_VERSION} QUIET)
57
58if(NOT PYSIDE_INCLUDE_DIR AND TARGET PySide${PYSIDE_MAJOR_VERSION}::pyside${PYSIDE_MAJOR_VERSION})
59get_property(PYSIDE_INCLUDE_DIR TARGET PySide${PYSIDE_MAJOR_VERSION}::pyside${PYSIDE_MAJOR_VERSION} PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
60endif(NOT PYSIDE_INCLUDE_DIR AND TARGET PySide${PYSIDE_MAJOR_VERSION}::pyside${PYSIDE_MAJOR_VERSION})
61
62if(NOT PYSIDE_INCLUDE_DIR)
63find_pip_package(PySide${PYSIDE_MAJOR_VERSION})
64if (PySide${PYSIDE_MAJOR_VERSION}_FOUND)
65set(PYSIDE_INCLUDE_DIR ${PySide${PYSIDE_MAJOR_VERSION}_INCLUDE_DIR})
66set(PYSIDE_LIBRARY ${PySide${PYSIDE_MAJOR_VERSION}_LIBRARY})
67endif()
68endif()
69
70find_package(PySide${PYSIDE_MAJOR_VERSION}Tools QUIET) # PySide utilities (uic & rcc executables)
71if(NOT PYSIDE_TOOLS_FOUND)
72message("=======================\n"
73"PySide${PYSIDE_MAJOR_VERSION}Tools not found.\n"
74"=======================\n")
75endif()
76
77file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/Ext/PySide)
78file(WRITE ${CMAKE_BINARY_DIR}/Ext/PySide/__init__.py "# PySide wrapper\n"
79"from PySide${PYSIDE_MAJOR_VERSION} import __version__\n"
80"from PySide${PYSIDE_MAJOR_VERSION} import __version_info__\n")
81file(WRITE ${CMAKE_BINARY_DIR}/Ext/PySide/QtCore.py "from PySide${PYSIDE_MAJOR_VERSION}.QtCore import *\n\n"
82"#QCoreApplication.CodecForTr=0\n"
83"#QCoreApplication.UnicodeUTF8=1\n")
84file(WRITE ${CMAKE_BINARY_DIR}/Ext/PySide/QtNetwork.py "from PySide${PYSIDE_MAJOR_VERSION}.QtNetwork import *\n")
85if(BUILD_GUI)
86file(WRITE ${CMAKE_BINARY_DIR}/Ext/PySide/QtGui.py "from PySide${PYSIDE_MAJOR_VERSION}.QtGui import *\n"
87"from PySide${PYSIDE_MAJOR_VERSION}.QtWidgets import *\n"
88"QHeaderView.setResizeMode = QHeaderView.setSectionResizeMode\n")
89file(WRITE ${CMAKE_BINARY_DIR}/Ext/PySide/QtSvg.py "from PySide${PYSIDE_MAJOR_VERSION}.QtSvg import *\n")
90file(WRITE ${CMAKE_BINARY_DIR}/Ext/PySide/QtUiTools.py "from PySide${PYSIDE_MAJOR_VERSION}.QtUiTools import *\n")
91file(WRITE ${CMAKE_BINARY_DIR}/Ext/PySide/QtWidgets.py "from PySide${PYSIDE_MAJOR_VERSION}.QtWidgets import *\n")
92if(PYSIDE_MAJOR_VERSION LESS 6)
93file(WRITE ${CMAKE_BINARY_DIR}/Ext/PySide/QtWebEngineWidgets.py "from PySide${PYSIDE_MAJOR_VERSION}.QtWebEngineWidgets import *\n")
94else()
95file(WRITE ${CMAKE_BINARY_DIR}/Ext/PySide/QtWebEngineWidgets.py "from PySide${PYSIDE_MAJOR_VERSION}.QtWebEngineWidgets import *\n"
96"from PySide${PYSIDE_MAJOR_VERSION}.QtWebEngineCore import QWebEnginePage\n")
97endif()
98endif()
99
100if(APPLE AND NOT BUILD_WITH_CONDA)
101install(
102DIRECTORY
103${CMAKE_BINARY_DIR}/Ext/PySide
104DESTINATION
105MacOS
106)
107else()
108install(
109DIRECTORY
110${CMAKE_BINARY_DIR}/Ext/PySide
111DESTINATION
112Ext
113)
114endif()
115
116# If shiboken cannot be found the build option will be set to OFF
117if(NOT SHIBOKEN_INCLUDE_DIR)
118message(WARNING "Shiboken${PYSIDE_MAJOR_VERSION} include files not found, FREECAD_USE_SHIBOKEN automatically set to OFF")
119set(FREECAD_USE_SHIBOKEN OFF)
120endif()
121
122# Now try to import the shiboken Python module and print a warning if it can't be loaded
123execute_process(
124COMMAND ${PYTHON_EXECUTABLE} -c "import shiboken${SHIBOKEN_MAJOR_VERSION}"
125RESULT_VARIABLE FAILURE
126OUTPUT_VARIABLE PRINT_OUTPUT
127)
128
129if(FAILURE)
130message(WARNING
131"==================================\n"
132"Shiboken${SHIBOKEN_MAJOR_VERSION} Python module not found.\n"
133"==================================\n")
134else()
135execute_process(
136COMMAND ${PYTHON_EXECUTABLE} -c "import shiboken${SHIBOKEN_MAJOR_VERSION};print(shiboken${SHIBOKEN_MAJOR_VERSION}.__version__, end='')"
137RESULT_VARIABLE FAILURE
138OUTPUT_VARIABLE Shiboken_VERSION
139)
140endif()
141
142# If PySide cannot be found the build option will be set to OFF
143if(NOT PYSIDE_INCLUDE_DIR)
144message(WARNING "PySide${PYSIDE_MAJOR_VERSION} include files not found, FREECAD_USE_PYSIDE automatically set to OFF")
145set(FREECAD_USE_PYSIDE OFF)
146endif()
147
148# Independent of the build option PySide modules must be loaded at runtime. Print a warning if it fails.
149execute_process(
150COMMAND ${PYTHON_EXECUTABLE} -c "import PySide${PYSIDE_MAJOR_VERSION};import os;print(os.path.dirname(PySide${PYSIDE_MAJOR_VERSION}.__file__), end='')"
151RESULT_VARIABLE FAILURE
152OUTPUT_VARIABLE PRINT_OUTPUT
153)
154if(FAILURE)
155message(WARNING
156"================================\n"
157"PySide${PYSIDE_MAJOR_VERSION} Python module not found.\n"
158"================================\n")
159else()
160execute_process(
161COMMAND ${PYTHON_EXECUTABLE} -c "import PySide${PYSIDE_MAJOR_VERSION};print(PySide${PYSIDE_MAJOR_VERSION}.__version__, end='')"
162RESULT_VARIABLE FAILURE
163OUTPUT_VARIABLE PySide_VERSION
164)
165message(STATUS "PySide ${PySide_VERSION} Python module found at ${PRINT_OUTPUT}.\n")
166endif()
167
168endmacro(SetupShibokenAndPyside)
169
170# Locate the include directory for a pip-installed package -- uses pip show to find the base pip
171# install directory, and then appends the package name and "/include" to the end
172macro(find_pip_package PACKAGE)
173execute_process(
174COMMAND ${PYTHON_EXECUTABLE} -m pip show ${PACKAGE}
175RESULT_VARIABLE FAILURE
176OUTPUT_VARIABLE PRINT_OUTPUT
177)
178if(NOT FAILURE)
179# Extract Name: and Location: lines and use them to construct the include directory
180string(REPLACE "\n" ";" PIP_OUTPUT_LINES ${PRINT_OUTPUT})
181foreach(LINE IN LISTS PIP_OUTPUT_LINES)
182STRING(FIND "${LINE}" "Name: " NAME_STRING_LOCATION)
183STRING(FIND "${LINE}" "Location: " LOCATION_STRING_LOCATION)
184if(${NAME_STRING_LOCATION} EQUAL 0)
185STRING(SUBSTRING "${LINE}" 6 -1 PIP_PACKAGE_NAME)
186elseif(${LOCATION_STRING_LOCATION} EQUAL 0)
187STRING(SUBSTRING "${LINE}" 10 -1 PIP_PACKAGE_LOCATION)
188endif()
189endforeach()
190message(STATUS "Found pip-installed ${PACKAGE} in ${PIP_PACKAGE_LOCATION}/${PIP_PACKAGE_NAME}")
191file(TO_NATIVE_PATH "${PIP_PACKAGE_LOCATION}/${PIP_PACKAGE_NAME}/include" INCLUDE_DIR)
192file(TO_NATIVE_PATH "${PIP_PACKAGE_LOCATION}/${PIP_PACKAGE_NAME}/lib" LIBRARY)
193if(EXISTS ${INCLUDE_DIR})
194set(${PACKAGE}_INCLUDE_DIR ${INCLUDE_DIR})
195else()
196message(STATUS "${PACKAGE} include directory '${INCLUDE_DIR}' does not exist")
197endif()
198if(EXISTS ${LIBRARY})
199set(${PACKAGE}_LIBRARY ${LIBRARY})
200else()
201message(STATUS "${PACKAGE} library directory '${LIBRARY}' does not exist")
202endif()
203set(${PACKAGE}_FOUND TRUE)
204endif()
205endmacro()
206
207
208# Macros similar to FindQt4.cmake's WRAP_UI and WRAP_RC, for the automatic generation of Python
209# code from Qt4's user interface ('.ui') and resource ('.qrc') files. These macros are called:
210# - PYSIDE_WRAP_UI
211# - PYSIDE_WRAP_RC
212
213MACRO(PYSIDE_WRAP_UI outfiles)
214if (NOT PYSIDE_UIC_EXECUTABLE)
215message(FATAL_ERROR "Qt uic is required for generating ${ARGN}")
216endif()
217FOREACH(it ${ARGN})
218GET_FILENAME_COMPONENT(outfile ${it} NAME_WE)
219GET_FILENAME_COMPONENT(infile ${it} ABSOLUTE)
220SET(outfile ${CMAKE_CURRENT_BINARY_DIR}/ui_${outfile}.py)
221if(WIN32 OR APPLE)
222ADD_CUSTOM_COMMAND(OUTPUT ${outfile}
223COMMAND ${PYSIDE_UIC_EXECUTABLE} ${UICOPTIONS} ${infile} -o ${outfile}
224MAIN_DEPENDENCY ${infile}
225)
226else()
227# Especially on Open Build Service we don't want changing date like
228# pyside2-uic generates in comments at beginning., which is why
229# we follow the tool command with a POSIX-friendly sed.
230ADD_CUSTOM_COMMAND(OUTPUT ${outfile}
231COMMAND "${PYSIDE_UIC_EXECUTABLE}" ${UICOPTIONS} "${infile}" -o "${outfile}"
232COMMAND sed "/^# /d" "${outfile}" >"${outfile}.tmp" && mv "${outfile}.tmp" "${outfile}"
233MAIN_DEPENDENCY "${infile}"
234)
235endif()
236list(APPEND ${outfiles} ${outfile})
237ENDFOREACH(it)
238ENDMACRO (PYSIDE_WRAP_UI)
239
240MACRO(PYSIDE_WRAP_RC outfiles)
241if (NOT PYSIDE_RCC_EXECUTABLE)
242message(FATAL_ERROR "Qt rcc is required for generating ${ARGN}")
243endif()
244FOREACH(it ${ARGN})
245GET_FILENAME_COMPONENT(outfile ${it} NAME_WE)
246GET_FILENAME_COMPONENT(infile ${it} ABSOLUTE)
247SET(outfile "${CMAKE_CURRENT_BINARY_DIR}/${outfile}_rc.py")
248#ADD_CUSTOM_TARGET(${it} ALL
249# DEPENDS ${outfile}
250#)
251if(WIN32 OR APPLE)
252ADD_CUSTOM_COMMAND(OUTPUT ${outfile}
253COMMAND ${PYSIDE_RCC_EXECUTABLE} ${RCCOPTIONS} ${infile} -o ${outfile}
254MAIN_DEPENDENCY ${infile}
255)
256else()
257# Especially on Open Build Service we don't want changing date like
258# pyside-rcc generates in comments at beginning, which is why
259# we follow the tool command with in-place sed.
260ADD_CUSTOM_COMMAND(OUTPUT "${outfile}"
261COMMAND "${PYSIDE_RCC_EXECUTABLE}" ${RCCOPTIONS} "${infile}" ${PY_ATTRIBUTE} -o "${outfile}"
262COMMAND sed "/^# /d" "${outfile}" >"${outfile}.tmp" && mv "${outfile}.tmp" "${outfile}"
263MAIN_DEPENDENCY "${infile}"
264)
265endif()
266list(APPEND ${outfiles} ${outfile})
267ENDFOREACH(it)
268ENDMACRO (PYSIDE_WRAP_RC)
269