Added PySide6 support

Task-Id: KDDW-27
This commit is contained in:
Renato Araujo Oliveira Filho
2021-01-11 16:31:49 -03:00
parent d80325ec8f
commit 4e79c68a7d
13 changed files with 499 additions and 25 deletions

View File

@@ -0,0 +1,134 @@
#
# SPDX-FileCopyrightText: 2020-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
# Author: Renato Araujo Oliveira Filho <renato.araujo@kdab.com>
#
# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
#
# Contact KDAB at <info@kdab.com> for commercial licensing options.
#
# PYSIDE_BASEDIR - Top of the PySide6 installation
# PYSIDE_INCLUDE_DIR - Directories to include to use PySide6
# PYSIDE_LIBRARY - Files to link against to use PySide6
# PYSIDE_TYPESYSTEMS - Type system files that should be used by other bindings extending PySide6
#
# You can install PySide6 from Qt repository with
# pip3 install --index-url=https://download.qt.io/official_releases/QtForPython --trusted-host download.qt.io pyside6
set(PYSIDE6_FOUND FALSE)
# extract python library basename
list(GET Python3_LIBRARIES 0 PYTHON_LIBRARY_FILENAME)
get_filename_component(PYTHON_LIBRARY_FILENAME ${PYTHON_LIBRARY_FILENAME} NAME)
execute_process(
COMMAND ${Python3_EXECUTABLE} -c "if True:
import os, sys
try:
import PySide6.QtCore as QtCore
print(os.path.dirname(QtCore.__file__))
except Exception as error:
print(error, file=sys.stderr)
exit()
"
OUTPUT_VARIABLE PYSIDE6_BASEDIR
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(PYSIDE6_BASEDIR)
set(PYSIDE_BASEDIR ${PYSIDE6_BASEDIR} CACHE PATH "Top level install of PySide6" FORCE)
execute_process(
COMMAND ${Python3_EXECUTABLE} -c "if True:
import os
import PySide6.QtCore as QtCore
print(os.path.basename(QtCore.__file__).split('.', 1)[1])
"
OUTPUT_VARIABLE PYSIDE6_SUFFIX
OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process(
COMMAND ${Python3_EXECUTABLE} -c "if True:
import os
import PySide6.QtCore as QtCore
print(';'.join(map(str, QtCore.__version_info__)))
"
OUTPUT_VARIABLE PYSIDE6_SO_VERSION
OUTPUT_STRIP_TRAILING_WHITESPACE
)
list(GET PYSIDE6_SO_VERSION 0 PYSIDE6_SO_MACRO_VERSION)
list(GET PYSIDE6_SO_VERSION 1 PYSIDE6_SO_MICRO_VERSION)
list(GET PYSIDE6_SO_VERSION 2 PYSIDE6_SO_MINOR_VERSION)
string(REPLACE ";" "." PYSIDE6_SO_VERSION "${PYSIDE6_SO_VERSION}")
if(NOT APPLE)
set(PYSIDE6_SUFFIX "${PYSIDE6_SUFFIX}.${PYSIDE6_SO_MACRO_VERSION}.${PYSIDE6_SO_MICRO_VERSION}")
else()
string(REPLACE ".so" "" PYSIDE6_SUFFIX ${PYSIDE6_SUFFIX})
set(PYSIDE6_SUFFIX "${PYSIDE6_SUFFIX}.${PYSIDE6_SO_MACRO_VERSION}.${PYSIDE6_SO_MICRO_VERSION}.dylib")
endif()
set(PYSIDE6_FOUND TRUE)
message(STATUS "PySide6 base dir: ${PYSIDE6_BASEDIR}" )
message(STATUS "PySide6 suffix: ${PYSIDE6_SUFFIX}")
endif()
if (PYSIDE6_FOUND)
#PySide
#===============================================================================
find_path(PYSIDE_INCLUDE_DIR
pyside.h
PATHS ${PYSIDE6_BASEDIR}/include ${PYSIDE6_CUSTOM_PREFIX}/include/PySide6
NO_DEFAULT_PATH)
# Platform specific library names
if(MSVC)
SET(PYSIDE_LIBRARY_BASENAMES "pyside6.abi3.lib")
elseif(CYGWIN)
SET(PYSIDE_LIBRARY_BASENAMES "")
elseif(WIN32)
SET(PYSIDE_LIBRARY_BASENAMES "libpyside6.${PYSIDE6_SUFFIX}")
else()
SET(PYSIDE_LIBRARY_BASENAMES "libpyside6.${PYSIDE6_SUFFIX}")
endif()
find_file(PYSIDE_LIBRARY
${PYSIDE_LIBRARY_BASENAMES}
PATHS ${PYSIDE6_BASEDIR} ${PYSIDE6_CUSTOM_PREFIX}/lib
NO_DEFAULT_PATH)
find_path(PYSIDE_TYPESYSTEMS
typesystem_core.xml
PATHS ${PYSIDE6_BASEDIR}/typesystems ${PYSIDE6_CUSTOM_PREFIX}/share/PySide6/typesystems
NO_DEFAULT_PATH)
endif()
if(PYSIDE6_FOUND)
message(STATUS "PySide include dir: ${PYSIDE_INCLUDE_DIR}")
message(STATUS "PySide library: ${PYSIDE_LIBRARY}")
message(STATUS "PySide typesystems: ${PYSIDE_TYPESYSTEMS}")
message(STATUS "PySide6 version: ${PYSIDE6_SO_VERSION}")
# Create PySide6 target
add_library(PySide6::pyside6 SHARED IMPORTED GLOBAL)
if(MSVC)
set_property(TARGET PySide6::pyside6 PROPERTY
IMPORTED_IMPLIB ${PYSIDE_LIBRARY})
endif()
set_property(TARGET PySide6::pyside6 PROPERTY
IMPORTED_LOCATION ${PYSIDE_LIBRARY})
set_property(TARGET PySide6::pyside6 APPEND PROPERTY
INTERFACE_INCLUDE_DIRECTORIES
${PYSIDE_INCLUDE_DIR}
${PYSIDE_INCLUDE_DIR}/QtCore/
${PYSIDE_INCLUDE_DIR}/QtGui/
${PYSIDE_INCLUDE_DIR}/QtWidgets/
${Python3_INCLUDE_DIRS}
)
endif()
find_package_handle_standard_args(PySide6
REQUIRED_VARS PYSIDE6_BASEDIR PYSIDE_INCLUDE_DIR PYSIDE_LIBRARY PYSIDE_TYPESYSTEMS
VERSION_VAR PYSIDE6_SO_VERSION
)

View File

@@ -0,0 +1,165 @@
#
# SPDX-FileCopyrightText: 2020-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
# Author: Renato Araujo Oliveira Filho <renato.araujo@kdab.com>
#
# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
#
# Contact KDAB at <info@kdab.com> for commercial licensing options.
#
# SHIBOKEN_INCLUDE_DIR - Directories to include to use SHIBOKEN
# SHIBOKEN_LIBRARY - Files to link against to use SHIBOKEN
# SHIBOKEN_BINARY - Executable name
# SHIBOKEN_BUILD_TYPE - Tells if Shiboken was compiled in Release or Debug mode.
# You can install Shiboken from Qt repository with
# pip3 install --index-url=https://download.qt.io/official_releases/QtForPython --trusted-host download.qt.io shiboken6-generator
set(SHIBOKEN_FOUND FALSE)
execute_process(
COMMAND ${Python3_EXECUTABLE} -c "if True:
import os
try:
import shiboken6_generator
print(shiboken6_generator.__path__[0])
except:
exit()
"
OUTPUT_VARIABLE SHIBOKEN_GENERATOR_BASEDIR
OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process(
COMMAND ${Python3_EXECUTABLE} -c "if True:
import os
try:
import shiboken6
print(shiboken6.__path__[0])
except:
exit()
"
OUTPUT_VARIABLE SHIBOKEN_BASEDIR
OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process(
COMMAND ${Python3_EXECUTABLE} -c "if True:
import os
import shiboken6
print(';'.join(filter(None, map(str, shiboken6.__version_info__))))
"
OUTPUT_VARIABLE SHIBOKEN_VERSION
OUTPUT_STRIP_TRAILING_WHITESPACE
)
list(GET SHIBOKEN_VERSION 0 SHIBOKEN_MACRO_VERSION)
list(GET SHIBOKEN_VERSION 1 SHIBOKEN_MICRO_VERSION)
list(GET SHIBOKEN_VERSION 2 SHIBOKEN_MINOR_VERSION)
string(REPLACE ";" "." SHIBOKEN_VERSION "${SHIBOKEN_VERSION}")
message(STATUS "ShibokenGenerator base dir: ${SHIBOKEN_GENERATOR_BASEDIR}")
message(STATUS "Shiboken base dir: ${SHIBOKEN_BASEDIR}")
message(STATUS "Shiboken custom path: ${SHIBOKEN_CUSTOM_PATH}")
if(SHIBOKEN_BASEDIR)
find_path(SHIBOKEN_INCLUDE_DIR
shiboken.h
PATHS ${SHIBOKEN_CUSTOM_PATH} ${SHIBOKEN_GENERATOR_BASEDIR}/include
NO_DEFAULT_PATH)
if(MSVC)
SET(SHIBOKEN_LIBRARY_BASENAMES "shiboken6.abi3.lib")
elseif(CYGWIN)
SET(SHIBOKEN_LIBRARY_BASENAMES "")
elseif(WIN32)
SET(SHIBOKEN_LIBRARY_BASENAMES "libshiboken6.${PYSIDE2_SUFFIX}")
elseif(APPLE)
SET(SHIBOKEN_LIBRARY_BASENAMES
libshiboken6.abi3.dylib
libshiboken6.abi3.${SHIBOKEN_MACRO_VERSION}.dylib
libshiboken6.abi3.${SHIBOKEN_MACRO_VERSION}.${SHIBOKEN_MICRO_VERSION}.dylib
libshiboken6.abi3.${SHIBOKEN_VERSION}.dylib
)
else()
SET(SHIBOKEN_LIBRARY_BASENAMES
libshiboken6.abi3.so
libshiboken6.abi3.so.${SHIBOKEN_MACRO_VERSION}
libshiboken6.abi3.so.${SHIBOKEN_MACRO_VERSION}.${SHIBOKEN_MICRO_VERSION}
libshiboken6.abi3.so.${SHIBOKEN_VERSION}
)
endif()
if (NOT SHIBOKEN_INCLUDE_DIR)
return()
endif()
set(SHIBOKEN_SEARCH_PATHS ${SHIBOKEN_CUSTOM_PATH})
list(APPEND SHIBOKEN_SEARCH_PATHS ${SHIBOKEN_BASEDIR})
list(APPEND SHIBOKEN_SEARCH_PATHS ${SHIBOKEN_GENERATOR_BASEDIR})
find_file(SHIBOKEN_LIBRARY
${SHIBOKEN_LIBRARY_BASENAMES}
PATHS ${SHIBOKEN_SEARCH_PATHS}
NO_DEFAULT_PATH)
find_program(SHIBOKEN_BINARY
shiboken6
PATHS ${SHIBOKEN_SEARCH_PATHS}
NO_DEFAULT_PATH
)
endif()
if (SHIBOKEN_INCLUDE_DIR AND SHIBOKEN_LIBRARY AND SHIBOKEN_BINARY)
set(SHIBOKEN_FOUND TRUE)
endif()
if(SHIBOKEN_FOUND)
endif()
if(MSVC)
# On Windows we must link to python3.dll that is a small library that links against python3x.dll
# that allow us to choose any python3x.dll at runtime
execute_process(
COMMAND ${Python3_EXECUTABLE} -c "if True:
for lib in '${Python3_LIBRARIES}'.split(';'):
if '/' in lib:
prefix, py = lib.rsplit('/', 1)
if py.startswith('python3'):
print(prefix + '/python3.lib')
break
"
OUTPUT_VARIABLE PYTHON_LIMITED_LIBRARIES
OUTPUT_STRIP_TRAILING_WHITESPACE
)
else()
# On Linux and MacOs our modules should not link with any python library
# that must be handled by the main process
set(PYTHON_LIMITED_LIBRARIES "")
endif()
if (SHIBOKEN_FOUND)
message(STATUS "Shiboken include dir: ${SHIBOKEN_INCLUDE_DIR}")
message(STATUS "Shiboken library: ${SHIBOKEN_LIBRARY}")
message(STATUS "Shiboken binary: ${SHIBOKEN_BINARY}")
message(STATUS "Shiboken version: ${SHIBOKEN_VERSION}")
# Create shiboke2 target
add_library(Shiboken6::libshiboken SHARED IMPORTED GLOBAL)
if(MSVC)
set_property(TARGET Shiboken6::libshiboken PROPERTY
IMPORTED_IMPLIB ${SHIBOKEN_LIBRARY})
endif()
set_property(TARGET Shiboken6::libshiboken PROPERTY
IMPORTED_LOCATION ${SHIBOKEN_LIBRARY})
set_property(TARGET Shiboken6::libshiboken APPEND PROPERTY
INTERFACE_INCLUDE_DIRECTORIES ${SHIBOKEN_INCLUDE_DIR} ${Python3_INCLUDE_DIRS})
set_property(TARGET Shiboken6::libshiboken APPEND PROPERTY
INTERFACE_LINK_LIBRARIES ${PYTHON_LIMITED_LIBRARIES})
# Generator target
add_executable(Shiboken6::shiboken IMPORTED GLOBAL)
set_property(TARGET Shiboken6::shiboken PROPERTY
IMPORTED_LOCATION ${SHIBOKEN_BINARY})
endif()
find_package_handle_standard_args(Shiboken6
REQUIRED_VARS SHIBOKEN_BASEDIR SHIBOKEN_INCLUDE_DIR SHIBOKEN_LIBRARY SHIBOKEN_BINARY
VERSION_VAR SHIBOKEN_VERSION
)

View File

@@ -0,0 +1,157 @@
#
# SPDX-FileCopyrightText: 2020-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
# Author: Renato Araujo Oliveira Filho <renato.araujo@kdab.com>
#
# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
#
# Contact KDAB at <info@kdab.com> for commercial licensing options.
#
if (NOT ${PROJECT_NAME}_PYTHON_BINDINGS_INSTALL_PREFIX)
SET(${PROJECT_NAME}_PYTHON_BINDINGS_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX} CACHE FILEPATH "Custom path to install python bindings.")
endif()
message(STATUS "PYTHON INSTALL PREFIX ${${PROJECT_NAME}_PYTHON_BINDINGS_INSTALL_PREFIX}")
if (WIN32)
set(PATH_SEP "\;")
else()
set(PATH_SEP ":")
endif()
if (NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 17)
endif()
# On macOS, check if Qt is a framework build. This affects how include paths should be handled.
get_target_property(QtCore_is_framework Qt6::Core FRAMEWORK)
if (QtCore_is_framework)
# Get the path to the framework dir.
list(GET Qt6Core_INCLUDE_DIRS 0 QT_INCLUDE_DIR)
get_filename_component(QT_FRAMEWORK_INCLUDE_DIR "${QT_INCLUDE_DIR}/../" ABSOLUTE)
# QT_INCLUDE_DIR points to the QtCore.framework directory, so we need to adjust this to point
# to the actual include directory, which has include files for non-framework parts of Qt.
get_filename_component(QT_INCLUDE_DIR "${QT_INCLUDE_DIR}/../../include" ABSOLUTE)
endif()
# Flags that we will pass to shiboken-generator
# --generator-set=shiboken: tells the generator that we want to use shiboken to generate code,
# a doc generator is also available
# --enable-parent-ctor-heuristic: Enable heuristics to detect parent relationship on constructors,
# this try to guess parent ownership based on the arguments of the constructors
# --enable-pyside-extensionsL: This will generate code for Qt based classes, adding extra attributes,
# like signal, slot;
# --enable-return-value-heuristic: Similar as --enable-parent-ctor-heuristic this use some logic to guess
# parent child relationship based on the returned argument
# --use-isnull-as-nb_nonzero: If a class have an isNull() const method, it will be used to compute
# the value of boolean casts.
# Example, QImage::isNull() will be used when on python side you do `if (myQImage)`
set(GENERATOR_EXTRA_FLAGS --generator-set=shiboken
--enable-parent-ctor-heuristic
--enable-pyside-extensions
--enable-return-value-heuristic
--use-isnull-as-nb_nonzero
-std=c++${CMAKE_CXX_STANDARD})
# 2017-04-24 The protected hack can unfortunately not be disabled, because
# Clang does produce linker errors when we disable the hack.
# But the ugly workaround in Python is replaced by a shiboken change.
if(WIN32 OR DEFINED AVOID_PROTECTED_HACK)
set(GENERATOR_EXTRA_FLAGS ${GENERATOR_EXTRA_FLAGS} --avoid-protected-hack)
add_definitions(-DAVOID_PROTECTED_HACK)
endif()
macro(make_path varname)
# accepts any number of path variables
string(REPLACE ";" "${PATH_SEP}" ${varname} "${ARGN}")
endmacro()
# Creates a PySide module target based on the arguments
# This will:
# 1 - Create a Cmake custom-target that call shiboken-generator passign the correct arguments
# 2 - Create a Cmake library target called "Py${LIBRARY_NAME}" the output name of this target
# will be changed to match PySide template
# Args:
# LIBRARY_NAME - The name of the output module
# TYPESYSTEM_PATHS - A list of paths where shiboken should look for typesystem files
# INCLUDE_PATHS - Include pahts necessary to parse your class. *This is not the same as build*
# OUTPUT_SOURCES - The files that will be generated by shiboken
# TARGET_INCLUDE_DIRS - This will be passed to target_include_directories
# TARGET_LINK_LIBRARIES - This will be passed to target_link_libraries
# GLOBAL_INCLUDE - A header-file that contains alls classes that will be generated
# TYPESYSTEM_XML - The target binding typesystem (that should be the full path)
# DEPENDS - This var will be passed to add_custom_command(DEPENDS) so a new generation will be
# trigger if one of these files changes
# MODULE_OUTPUT_DIR - Where the library file should be stored
macro(CREATE_PYTHON_BINDINGS
LIBRARY_NAME
TYPESYSTEM_PATHS
INCLUDE_PATHS
OUTPUT_SOURCES
TARGET_INCLUDE_DIRS
TARGET_LINK_LIBRARIES
GLOBAL_INCLUDE
TYPESYSTEM_XML
DEPENDS
MODULE_OUTPUT_DIR)
# Transform the path separators into something shiboken understands.
make_path(shiboken_include_dirs ${INCLUDE_PATHS})
make_path(shiboken_typesystem_dirs ${TYPESYSTEM_PATHS})
get_property(raw_python_dir_include_dirs DIRECTORY PROPERTY INCLUDE_DIRECTORIES)
make_path(python_dir_include_dirs ${raw_python_dir_include_dirs})
set(shiboken_include_dirs "${shiboken_include_dirs}${PATH_SEP}${python_dir_include_dirs}")
set(shiboken_framework_include_dirs_option "")
if(CMAKE_HOST_APPLE)
set(shiboken_framework_include_dirs "${QT_FRAMEWORK_INCLUDE_DIR}")
make_path(shiboken_framework_include_dirs ${shiboken_framework_include_dirs})
set(shiboken_framework_include_dirs_option "--framework-include-paths=${shiboken_framework_include_dirs}")
endif()
set_property(SOURCE ${OUTPUT_SOURCES} PROPERTY SKIP_AUTOGEN ON)
add_custom_command(OUTPUT ${OUTPUT_SOURCES}
COMMAND $<TARGET_PROPERTY:Shiboken6::shiboken,LOCATION> ${GENERATOR_EXTRA_FLAGS}
${GLOBAL_INCLUDE}
--include-paths=${shiboken_include_dirs}
--typesystem-paths=${shiboken_typesystem_dirs}
${shiboken_framework_include_dirs_option}
--output-directory=${CMAKE_CURRENT_BINARY_DIR}
${TYPESYSTEM_XML}
DEPENDS ${TYPESYSTEM_XML} ${DEPENDS}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Running generator for ${LIBRARY_NAME} binding...")
set(TARGET_NAME "Py${LIBRARY_NAME}")
set(MODULE_NAME "${LIBRARY_NAME}")
add_library(${TARGET_NAME} MODULE ${OUTPUT_SOURCES})
set_target_properties(${TARGET_NAME} PROPERTIES
PREFIX ""
OUTPUT_NAME ${MODULE_NAME}
LIBRARY_OUTPUT_DIRECTORY ${MODULE_OUTPUT_DIR}
)
if(WIN32)
set_target_properties(${TARGET_NAME} PROPERTIES SUFFIX ".pyd")
endif()
target_include_directories(${TARGET_NAME} PUBLIC
${TARGET_INCLUDE_DIRS}
${PYSIDE_EXTRA_INCLUDES}
)
target_link_libraries(${TARGET_NAME}
${TARGET_LINK_LIBRARIES}
PySide6::pyside6
Shiboken6::libshiboken
)
target_compile_definitions(${TARGET_NAME}
PRIVATE Py_LIMITED_API=0x03050000
)
if(APPLE)
set_property(TARGET ${TARGET_NAME} APPEND PROPERTY
LINK_FLAGS "-undefined dynamic_lookup")
endif()
install(TARGETS ${TARGET_NAME}
LIBRARY DESTINATION ${${PROJECT_NAME}_PYTHON_BINDINGS_INSTALL_PREFIX}/${TARGET_NAME})
endmacro()