diff --git a/CMakeLists.txt b/CMakeLists.txt
index 919969e..e3ddec5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -11,6 +11,7 @@ install(FILES
cmake/shiboken_helper.cmake
cmake/sip_configure.py
cmake/sip_helper.cmake
+ cmake/pyside_config.py
DESTINATION share/${PROJECT_NAME}/cmake)
if(BUILD_TESTING)
diff --git a/cmake/pyside_config.py b/cmake/pyside_config.py
new file mode 100755
index 0000000..2282e43
--- /dev/null
+++ b/cmake/pyside_config.py
@@ -0,0 +1,341 @@
+#!/usr/bin/python3
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+from enum import Enum
+from glob import glob
+import os
+import re
+import sys
+import sysconfig
+
+
+PYSIDE = 'pyside6'
+PYSIDE_MODULE = 'PySide6'
+SHIBOKEN = 'shiboken6'
+
+
+class Package(Enum):
+ SHIBOKEN_MODULE = 1
+ SHIBOKEN_GENERATOR = 2
+ PYSIDE_MODULE = 3
+
+
+generic_error = ('Did you forget to activate your virtualenv? Or perhaps'
+ f' you forgot to build / install {PYSIDE_MODULE} into your currently'
+ ' active Python environment?')
+pyside_error = f'Unable to locate {PYSIDE_MODULE}. {generic_error}'
+shiboken_module_error = f'Unable to locate {SHIBOKEN}-module. {generic_error}'
+shiboken_generator_error = f'Unable to locate shiboken-generator. {generic_error}'
+pyside_libs_error = f'Unable to locate the PySide shared libraries. {generic_error}'
+python_link_error = 'Unable to locate the Python library for linking.'
+python_include_error = 'Unable to locate the Python include headers directory.'
+
+options = []
+
+# option, function, error, description
+options.append(('--shiboken-module-path',
+ lambda: find_shiboken_module(),
+ shiboken_module_error,
+ 'Print shiboken module location'))
+options.append(('--shiboken-generator-path',
+ lambda: find_shiboken_generator(),
+ shiboken_generator_error,
+ 'Print shiboken generator location'))
+options.append(('--pyside-path', lambda: find_pyside(), pyside_error,
+ f'Print {PYSIDE_MODULE} location'))
+
+options.append(('--python-include-path',
+ lambda: get_python_include_path(),
+ python_include_error,
+ 'Print Python include path'))
+options.append(('--shiboken-generator-include-path',
+ lambda: get_package_include_path(Package.SHIBOKEN_GENERATOR),
+ pyside_error,
+ 'Print shiboken generator include paths'))
+options.append(('--pyside-include-path',
+ lambda: get_package_include_path(Package.PYSIDE_MODULE),
+ pyside_error,
+ 'Print PySide6 include paths'))
+
+options.append(('--python-link-flags-qmake', lambda: python_link_flags_qmake(), python_link_error,
+ 'Print python link flags for qmake'))
+options.append(('--python-link-flags-cmake', lambda: python_link_flags_cmake(), python_link_error,
+ 'Print python link flags for cmake'))
+
+options.append(('--shiboken-module-qmake-lflags',
+ lambda: get_package_qmake_lflags(Package.SHIBOKEN_MODULE), pyside_error,
+ 'Print shiboken6 shared library link flags for qmake'))
+options.append(('--pyside-qmake-lflags',
+ lambda: get_package_qmake_lflags(Package.PYSIDE_MODULE), pyside_error,
+ 'Print PySide6 shared library link flags for qmake'))
+
+options.append(('--shiboken-module-shared-libraries-qmake',
+ lambda: get_shared_libraries_qmake(Package.SHIBOKEN_MODULE), pyside_libs_error,
+ "Print paths of shiboken shared libraries (.so's, .dylib's, .dll's) for qmake"))
+options.append(('--shiboken-module-shared-libraries-cmake',
+ lambda: get_shared_libraries_cmake(Package.SHIBOKEN_MODULE), pyside_libs_error,
+ "Print paths of shiboken shared libraries (.so's, .dylib's, .dll's) for cmake"))
+
+options.append(('--pyside-shared-libraries-qmake',
+ lambda: get_shared_libraries_qmake(Package.PYSIDE_MODULE), pyside_libs_error,
+ "Print paths of f{PYSIDE_MODULE} shared libraries (.so's, .dylib's, .dll's) "
+ 'for qmake'))
+options.append(('--pyside-shared-libraries-cmake',
+ lambda: get_shared_libraries_cmake(Package.PYSIDE_MODULE), pyside_libs_error,
+ f"Print paths of {PYSIDE_MODULE} shared libraries (.so's, .dylib's, .dll's) "
+ 'for cmake'))
+
+options_usage = ''
+for i, (flag, _, _, description) in enumerate(options):
+ options_usage += f' {flag:<45} {description}'
+ if i < len(options) - 1:
+ options_usage += '\n'
+
+usage = f"""
+Utility to determine include/link options of shiboken/PySide and Python for qmake/CMake projects
+that would like to embed or build custom shiboken/PySide bindings.
+
+Usage: pyside_config.py [option]
+Options:
+{options_usage}
+ -a Print all options and their values
+ --help/-h Print this help
+"""
+
+option = sys.argv[1] if len(sys.argv) == 2 else '-a'
+if option == '-h' or option == '--help':
+ print(usage)
+ sys.exit(0)
+
+
+def clean_path(path):
+ return path if sys.platform != 'win32' else path.replace('\\', '/')
+
+
+def shared_library_suffix():
+ if sys.platform == 'win32':
+ return 'lib'
+ elif sys.platform == 'darwin':
+ return 'dylib'
+ # Linux
+ else:
+ return 'so.*'
+
+
+def import_suffixes():
+ import importlib.machinery
+ return importlib.machinery.EXTENSION_SUFFIXES
+
+
+def is_debug():
+ debug_suffix = '_d.pyd' if sys.platform == 'win32' else '_d.so'
+ return any(s.endswith(debug_suffix) for s in import_suffixes())
+
+
+def shared_library_glob_pattern():
+ glob = '*.' + shared_library_suffix()
+ return glob if sys.platform == 'win32' else 'lib' + glob
+
+
+def filter_shared_libraries(libs_list):
+ def predicate(lib_name):
+ basename = os.path.basename(lib_name)
+ if 'shiboken' in basename or 'pyside6' in basename:
+ return True
+ return False
+ result = [lib for lib in libs_list if predicate(lib)]
+ return result
+
+
+# Return qmake link option for a library file name
+def link_option(lib):
+ # On Linux:
+ # Since we cannot include symlinks with wheel packages
+ # we are using an absolute path for the libpyside and libshiboken
+ # libraries when compiling the project
+ baseName = os.path.basename(lib)
+ link = ' -l'
+ if sys.platform in ['linux', 'linux2']: # Linux: 'libfoo.so' -> '/absolute/path/libfoo.so'
+ link = lib
+ elif sys.platform in ['darwin']: # Darwin: 'libfoo.so' -> '-lfoo'
+ link += os.path.splitext(baseName[3:])[0]
+ else: # Windows: 'libfoo.dll' -> 'libfoo.dll'
+ link += os.path.splitext(baseName)[0]
+ return link
+
+
+# Locate PySide6 via sys.path package path.
+def find_pyside():
+ return find_package_path(PYSIDE_MODULE)
+
+
+def find_shiboken_module():
+ return find_package_path(SHIBOKEN)
+
+
+def find_shiboken_generator():
+ return find_package_path(f'{SHIBOKEN}_generator')
+
+
+def find_package(which_package):
+ if which_package == Package.SHIBOKEN_MODULE:
+ return find_shiboken_module()
+ if which_package == Package.SHIBOKEN_GENERATOR:
+ return find_shiboken_generator()
+ if which_package == Package.PYSIDE_MODULE:
+ return find_pyside()
+ return None
+
+
+def find_package_path(dir_name):
+ for p in sys.path:
+ if 'site-' in p or 'dist-' in p:
+ package = os.path.join(p, dir_name)
+ if os.path.exists(package):
+ return clean_path(os.path.realpath(package))
+ return None
+
+
+# Return version as 'x.y' (e.g. 3.9, 3.12, etc)
+def python_version():
+ return str(sys.version_info[0]) + '.' + str(sys.version_info[1])
+
+
+def get_python_include_path():
+ return sysconfig.get_path('include')
+
+
+def python_link_flags_qmake():
+ flags = python_link_data()
+ if sys.platform == 'win32':
+ libdir = flags['libdir']
+ # This will add the '~1' shortcut for directories that
+ # contain white spaces
+ # e.g.: 'Program Files' to 'Progra~1'
+ for d in libdir.split('\\'):
+ if ' ' in d:
+ libdir = libdir.replace(d, d.split(' ')[0][:-1] + '~1')
+ lib_flags = flags['lib']
+ return f'-L{libdir} -l{lib_flags}'
+ elif sys.platform == 'darwin':
+ libdir = flags['libdir']
+ lib_flags = flags['lib']
+ return f'-L{libdir} -l{lib_flags}'
+ else:
+ # Linux and anything else
+ libdir = flags['libdir']
+ lib_flags = flags['lib']
+ return f'-L{libdir} -l{lib_flags}'
+
+
+def python_link_flags_cmake():
+ flags = python_link_data()
+ libdir = flags['libdir']
+ lib = re.sub(r'.dll$', '.lib', flags['lib'])
+ return f'{libdir};{lib}'
+
+
+def python_link_data():
+ # @TODO Fix to work with static builds of Python
+ libdir = sysconfig.get_config_var('LIBDIR')
+ if libdir is None:
+ libdir = os.path.abspath(os.path.join(
+ sysconfig.get_config_var('LIBDEST'), '..', 'libs'))
+ version = python_version()
+ version_no_dots = version.replace('.', '')
+
+ flags = {}
+ flags['libdir'] = libdir
+ if sys.platform == 'win32':
+ suffix = '_d' if is_debug() else ''
+ flags['lib'] = f'python{version_no_dots}{suffix}'
+
+ elif sys.platform == 'darwin':
+ flags['lib'] = f'python{version}'
+
+ # Linux and anything else
+ else:
+ flags['lib'] = f'python{version}{sys.abiflags}'
+
+ return flags
+
+
+def get_package_include_path(which_package):
+ package_path = find_package(which_package)
+ if package_path is None:
+ return None
+
+ includes = f'{package_path}/include'
+
+ return includes
+
+
+def get_package_qmake_lflags(which_package):
+ package_path = find_package(which_package)
+ if package_path is None:
+ return None
+
+ link = f'-L{package_path}'
+ glob_result = glob(os.path.join(package_path, shared_library_glob_pattern()))
+ for lib in filter_shared_libraries(glob_result):
+ link += ' '
+ link += link_option(lib)
+ return link
+
+
+def get_shared_libraries_data(which_package):
+ package_path = find_package(which_package)
+ if package_path is None:
+ return None
+
+ glob_result = glob(os.path.join(package_path, shared_library_glob_pattern()))
+ filtered_libs = filter_shared_libraries(glob_result)
+ libs = []
+ if sys.platform == 'win32':
+ for lib in filtered_libs:
+ libs.append(os.path.realpath(lib))
+ else:
+ for lib in filtered_libs:
+ libs.append(lib)
+ return libs
+
+
+def get_shared_libraries_qmake(which_package):
+ libs = get_shared_libraries_data(which_package)
+ if libs is None:
+ return None
+
+ if sys.platform == 'win32':
+ if not libs:
+ return ''
+ dlls = ''
+ for lib in libs:
+ dll = os.path.splitext(lib)[0] + '.dll'
+ dlls += dll + ' '
+
+ return dlls
+ else:
+ libs_string = ''
+ for lib in libs:
+ libs_string += lib + ' '
+ return libs_string
+
+
+def get_shared_libraries_cmake(which_package):
+ libs = get_shared_libraries_data(which_package)
+ result = ';'.join(libs)
+ return result
+
+
+print_all = option == '-a'
+for argument, handler, error, _ in options:
+ if option == argument or print_all:
+ handler_result = handler()
+ if handler_result is None:
+ sys.exit(error)
+
+ line = handler_result
+ if print_all:
+ line = f'{argument:<40}: {line}'
+ print(line)
diff --git a/cmake/shiboken_helper.cmake b/cmake/shiboken_helper.cmake
index 7624157..acd3855 100644
--- a/cmake/shiboken_helper.cmake
+++ b/cmake/shiboken_helper.cmake
@@ -21,48 +21,102 @@ if(__PYTHON_QT_BINDING_SHIBOKEN_HELPER_INCLUDED)
endif()
set(__PYTHON_QT_BINDING_SHIBOKEN_HELPER_INCLUDED TRUE)
+find_package(QT NAMES Qt5 Qt6 REQUIRED)
+
# In CMake 3.27 and later, FindPythonInterp and FindPythonLibs are deprecated.
# However, Shiboken2 as packaged in Ubuntu 24.04 still use them, so set CMP0148 to
# "OLD" to silence this warning.
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.27.0")
cmake_policy(SET CMP0148 OLD)
endif()
-find_package(Shiboken2 QUIET)
-if(Shiboken2_FOUND)
- message(STATUS "Found Shiboken2 version ${Shiboken2_VERSION}")
- if(NOT ${Shiboken2_VERSION} VERSION_LESS "5.13")
- get_property(SHIBOKEN_INCLUDE_DIR TARGET Shiboken2::libshiboken PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
- get_property(SHIBOKEN_LIBRARY TARGET Shiboken2::libshiboken PROPERTY LOCATION)
- set(SHIBOKEN_BINARY Shiboken2::shiboken2)
- endif()
- message(STATUS "Using SHIBOKEN_INCLUDE_DIR: ${SHIBOKEN_INCLUDE_DIR}")
- message(STATUS "Using SHIBOKEN_LIBRARY: ${SHIBOKEN_LIBRARY}")
- message(STATUS "Using SHIBOKEN_BINARY: ${SHIBOKEN_BINARY}")
-endif()
+# set(QT_VERSION_MAJOR 6)
+# if(${QT_VERSION_MAJOR} GREATER "5")
+ # Macro to get various pyside / python include / link flags and paths.
+ # Uses the not entirely supported utils/pyside_config.py file.
-find_package(PySide2 QUIET)
-if(PySide2_FOUND)
- message(STATUS "Found PySide2 version ${PySide2_VERSION}")
- if(NOT ${PySide2_VERSION} VERSION_LESS "5.13")
- get_property(PYSIDE_INCLUDE_DIR TARGET PySide2::pyside2 PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
- get_property(PYSIDE_LIBRARY TARGET PySide2::pyside2 PROPERTY LOCATION)
+ # Use provided python interpreter if given.
+ if(NOT python_interpreter)
+ find_program(python_interpreter "python3")
+ if(NOT python_interpreter)
+ message(FATAL_ERROR
+ "No Python interpreter could be found. Make sure python is in PATH.")
+ endif()
endif()
- message(STATUS "Using PYSIDE_INCLUDE_DIR: ${PYSIDE_INCLUDE_DIR}")
- message(STATUS "Using PYSIDE_LIBRARY: ${PYSIDE_LIBRARY}")
-endif()
+ message(STATUS "Using python interpreter: ${python_interpreter}")
+
+ macro(pyside_config option output_var)
+ if(${ARGC} GREATER 2)
+ set(is_list ${ARGV2})
+ else()
+ set(is_list "")
+ endif()
-if(Shiboken2_FOUND AND PySide2_FOUND)
- message(STATUS "Shiboken binding generator available.")
+ find_package(python_qt_binding REQUIRED)
+ execute_process(
+ COMMAND ${python_interpreter} ${python_qt_binding_DIR}/pyside_config.py
+ ${option}
+ OUTPUT_VARIABLE ${output_var}
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ if("${${output_var}}" STREQUAL "")
+ message(FATAL_ERROR "Error: Calling pyside_config.py ${option} returned no output.")
+ endif()
+ if(is_list)
+ string(REPLACE " " ";" ${output_var} "${${output_var}}")
+ endif()
+ endmacro()
+
+ pyside_config(--pyside-shared-libraries-cmake pyside6_lib)
+ pyside_config(--pyside-include-path pyside6_includes)
+ pyside_config(--shiboken-module-shared-libraries-cmake shiboken6_lib)
+ pyside_config(--shiboken-generator-include-path shiboken6_includes)
+ pyside_config(--shiboken-generator-path shiboken6_generator_path)
+
+ set(PYSIDE_LIBRARY ${pyside6_lib})
+ set(PYSIDE_INCLUDE_DIR ${pyside6_includes})
+ set(SHIBOKEN_LIBRARY ${shiboken6_lib})
+ set(SHIBOKEN_INCLUDE_DIR ${shiboken6_includes};${shiboken6_generator_path}/include)
+ set(SHIBOKEN_BINARY "${shiboken6_generator_path}/shiboken6")
set(shiboken_helper_FOUND TRUE)
-else()
- message(STATUS "Shiboken binding generator NOT available.")
- set(shiboken_helper_NOTFOUND TRUE)
-endif()
+# else()
+# find_package(Shiboken2 QUIET)
+# if(Shiboken2_FOUND)
+# message(STATUS "Found Shiboken2 version ${Shiboken2_VERSION}")
+# if(NOT ${Shiboken2_VERSION} VERSION_LESS "5.13")
+# get_property(SHIBOKEN_INCLUDE_DIR TARGET Shiboken2::libshiboken PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
+# get_property(SHIBOKEN_LIBRARY TARGET Shiboken2::libshiboken PROPERTY LOCATION)
+# set(SHIBOKEN_BINARY Shiboken2::shiboken2)
+# endif()
+# endif()
+# find_package(PySide2 QUIET)
+# if(PySide2_FOUND)
+# message(STATUS "Found PySide2 version ${PySide2_VERSION}")
+# if(NOT ${PySide2_VERSION} VERSION_LESS "5.13")
+# get_property(PYSIDE_INCLUDE_DIR TARGET PySide2::pyside2 PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
+# get_property(PYSIDE_LIBRARY TARGET PySide2::pyside2 PROPERTY LOCATION)
+# endif()
+# endif()
+
+# if(Shiboken2_FOUND AND PySide2_FOUND)
+# message(STATUS "Shiboken binding generator available.")
+# set(shiboken_helper_FOUND TRUE)
+# else()
+# message(STATUS "Shiboken binding generator NOT available.")
+# set(shiboken_helper_NOTFOUND TRUE)
+# endif()
+# endif()
+
+message(STATUS "Using SHIBOKEN_INCLUDE_DIR: ${SHIBOKEN_INCLUDE_DIR}")
+message(STATUS "Using SHIBOKEN_LIBRARY: ${SHIBOKEN_LIBRARY}")
+message(STATUS "Using SHIBOKEN_BINARY: ${SHIBOKEN_BINARY}")
+message(STATUS "Using PYSIDE_INCLUDE_DIR: ${PYSIDE_INCLUDE_DIR}")
+message(STATUS "Using PYSIDE_LIBRARY: ${PYSIDE_LIBRARY}")
macro(_shiboken_generator_command VAR GLOBAL TYPESYSTEM INCLUDE_PATH BUILD_DIR)
# Add includes from current directory, Qt, PySide and compiler specific dirs
get_directory_property(SHIBOKEN_HELPER_INCLUDE_DIRS INCLUDE_DIRECTORIES)
+ message("**** SHIBOKEN_HELPER_INCLUDE_DIRS " ${SHIBOKEN_HELPER_INCLUDE_DIRS})
list(APPEND SHIBOKEN_HELPER_INCLUDE_DIRS
${QT_INCLUDE_DIR}
${PYSIDE_INCLUDE_DIR}
@@ -78,10 +132,36 @@ macro(_shiboken_generator_command VAR GLOBAL TYPESYSTEM INCLUDE_PATH BUILD_DIR)
--enable-pyside-extensions
-std=c++17
--include-paths=${INCLUDE_PATH_WITH_COLONS}${SHIBOKEN_HELPER_INCLUDE_DIRS_WITH_COLONS}
- --typesystem-paths=${PYSIDE_TYPESYSTEMS}
- --output-directory=${BUILD_DIR} ${GLOBAL} ${TYPESYSTEM})
+ --typesystem-paths="/usr/local/lib/python3.12/dist-packages/PySide6/typesystems/"
+ --output-directory=${BUILD_DIR} ${GLOBAL} ${TYPESYSTEM}
+ --no-suppress-warnings)
endmacro()
+macro(_shiboken_generator_command6 VAR GLOBAL TYPESYSTEM INCLUDE_PATH BUILD_DIR)
+ # Add includes from current directory, Qt, PySide and compiler specific dirs
+ get_directory_property(SHIBOKEN_HELPER_INCLUDE_DIRS INCLUDE_DIRECTORIES)
+ list(APPEND SHIBOKEN_HELPER_INCLUDE_DIRS
+ ${QT_INCLUDE_DIR}
+ ${PYSIDE_INCLUDE_DIR}
+ ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES})
+ # See ticket https://code.ros.org/trac/ros-pkg/ticket/5219
+ set(SHIBOKEN_HELPER_INCLUDE_DIRS_WITH_COLONS "")
+ foreach(dir ${SHIBOKEN_HELPER_INCLUDE_DIRS})
+ set(SHIBOKEN_HELPER_INCLUDE_DIRS_WITH_COLONS "${SHIBOKEN_HELPER_INCLUDE_DIRS_WITH_COLONS}:${dir}")
+ endforeach()
+ string(REPLACE ";" ":" INCLUDE_PATH_WITH_COLONS "${INCLUDE_PATH}")
+ message(SHIBOKEN_BINARY ${SHIBOKEN_BINARY})
+ set(${VAR} ${SHIBOKEN_BINARY}
+ --generator-set=shiboken
+ --enable-pyside-extensions
+ --language-level=c++17
+ --include-paths=${INCLUDE_PATH_WITH_COLONS}${SHIBOKEN_HELPER_INCLUDE_DIRS_WITH_COLONS}:/home/ahcorde/ros2_rolling/qt6-env/lib/python3.12/site-packages/shiboken6/include
+ --typesystem-paths="${PYSIDE_INCLUDE_DIR}/../typesystems/"
+ --output-directory=${BUILD_DIR} ${GLOBAL} ${TYPESYSTEM}
+ --enable-parent-ctor-heuristic
+ --enable-return-value-heuristic --use-isnull-as-nb-bool
+ --avoid-protected-hack)
+endmacro()
#
# Run the Shiboken generator.
@@ -115,6 +195,17 @@ function(shiboken_generator PROJECT_NAME GLOBAL TYPESYSTEM WORKING_DIR GENERATED
)
endfunction()
+function(shiboken_generator6 PROJECT_NAME GLOBAL TYPESYSTEM WORKING_DIR GENERATED_SRCS HDRS INCLUDE_PATH BUILD_DIR)
+ _shiboken_generator_command6(COMMAND "${GLOBAL}" "${TYPESYSTEM}" "${INCLUDE_PATH}" "${BUILD_DIR}")
+ message("comand ${COMMAND} ")
+ add_custom_command(
+ OUTPUT ${GENERATED_SRCS}
+ COMMAND ${COMMAND}
+ DEPENDS ${GLOBAL} ${TYPESYSTEM} ${HDRS}
+ WORKING_DIRECTORY ${WORKING_DIR}
+ COMMENT "Running Shiboken generator for ${PROJECT_NAME} Python bindings..."
+ )
+endfunction()
#
# Add the Shiboken/PySide specific include directories.
@@ -137,7 +228,7 @@ function(shiboken_include_directories PROJECT_NAME QT_COMPONENTS)
set(shiboken_INCLUDE_DIRECTORIES ${shiboken_INCLUDE_DIRECTORIES} ${PYSIDE_INCLUDE_DIR}/${component})
endforeach()
- include_directories(${PROJECT_NAME} ${shiboken_INCLUDE_DIRECTORIES})
+ include_directories(${PROJECT_NAME} ${shiboken_INCLUDE_DIRECTORIES} /home/ahcorde/ros2_rolling/qt6-env/lib/python3.12/site-packages/shiboken6/include)
endfunction()
diff --git a/cmake/sip_configure.py b/cmake/sip_configure.py
index 5210ee5..619ed1b 100644
--- a/cmake/sip_configure.py
+++ b/cmake/sip_configure.py
@@ -6,19 +6,19 @@
import sys
import tempfile
-import PyQt5
-from PyQt5 import QtCore
+import PyQt6
+from PyQt6 import QtCore
import sipconfig
-libqt5_rename = False
+libqt6_rename = False
class Configuration(sipconfig.Configuration):
def __init__(self):
env = copy.copy(os.environ)
- env['QT_SELECT'] = '5'
- qmake_exe = 'qmake-qt5' if shutil.which('qmake-qt5') else 'qmake'
+ env['QT_SELECT'] = '6'
+ qmake_exe = 'qmake-qt6' if shutil.which('qmake-qt6') else 'qmake'
qtconfig = subprocess.check_output(
[qmake_exe, '-query'], env=env, universal_newlines=True)
qtconfig = dict(line.split(':', 1) for line in qtconfig.splitlines())
@@ -36,15 +36,15 @@ def __init__(self):
if os.path.exists(os.path.join(qtconfig['QT_INSTALL_LIBS'], 'QtCore.framework')):
pyqtconfig['qt_framework'] = 1
else:
- global libqt5_rename
- libqt5_rename = True
+ global libqt6_rename
+ libqt6_rename = True
sipconfig.Configuration.__init__(self, [pyqtconfig])
macros = sipconfig._default_macros.copy()
macros['INCDIR_QT'] = qtconfig['QT_INSTALL_HEADERS']
macros['LIBDIR_QT'] = qtconfig['QT_INSTALL_LIBS']
- macros['MOC'] = 'moc-qt5' if shutil.which('moc-qt5') else 'moc'
+ macros['MOC'] = 'moc-qt6' if shutil.which('moc-qt6') else 'moc'
self.set_build_macros(macros)
@@ -70,20 +70,20 @@ def get_sip_dir_flags(config):
candidate_sip_dirs = []
# Archlinux installs sip files here by default
- candidate_sip_dirs.append(os.path.join(PyQt5.__path__[0], 'bindings'))
+ candidate_sip_dirs.append(os.path.join(PyQt6.__path__[0], 'bindings'))
# sip4 installs here by default
- candidate_sip_dirs.append(os.path.join(sipconfig._pkg_config['default_sip_dir'], 'PyQt5'))
+ candidate_sip_dirs.append(os.path.join(sipconfig._pkg_config['default_sip_dir'], 'PyQt6'))
# Homebrew installs sip files here by default
- candidate_sip_dirs.append(os.path.join(sipconfig._pkg_config['default_sip_dir'], 'Qt5'))
+ candidate_sip_dirs.append(os.path.join(sipconfig._pkg_config['default_sip_dir'], 'Qt6'))
for sip_dir in candidate_sip_dirs:
if os.path.exists(sip_dir):
return sip_dir, sip_flags
- raise FileNotFoundError('The sip directory for PyQt5 could not be located. Please ensure' +
- ' that PyQt5 is installed')
+ raise FileNotFoundError('The sip directory for PyQt6 could not be located. Please ensure' +
+ ' that PyQt6 is installed')
if len(sys.argv) != 8:
@@ -177,10 +177,10 @@ def custom_platform_lib_function(self, clib, framework=0):
if os.path.isabs(clib) or clib.startswith('-l'):
return clib
- global libqt5_rename
- # sip renames libs to Qt5 automatically on Linux, but not on macOS
- if libqt5_rename and not framework and clib.startswith('Qt') and not clib.startswith('Qt5'):
- return '-lQt5' + clib[2:]
+ global libqt6_rename
+ # sip renames libs to Qt6 automatically on Linux, but not on macOS
+ if libqt6_rename and not framework and clib.startswith('Qt') and not clib.startswith('Qt6'):
+ return '-lQt6' + clib[2:]
return default_platform_lib_function(self, clib, framework)
diff --git a/cmake/sip_helper.cmake b/cmake/sip_helper.cmake
index a5ac3c2..a263fea 100644
--- a/cmake/sip_helper.cmake
+++ b/cmake/sip_helper.cmake
@@ -93,10 +93,13 @@ function(build_sip_binding PROJECT_NAME SIP_FILE)
set(LIBRARY_DIRS ${${PROJECT_NAME}_LIBRARY_DIRS})
set(LDFLAGS_OTHER ${${PROJECT_NAME}_LDFLAGS_OTHER})
+ make_directory(${SIP_BUILD_DIR})
+
add_custom_command(
OUTPUT ${SIP_BUILD_DIR}/Makefile
- COMMAND ${Python3_EXECUTABLE} ${sip_SIP_CONFIGURE} ${SIP_BUILD_DIR} ${SIP_FILE} ${sip_LIBRARY_DIR}
- \"${INCLUDE_DIRS}\" \"${LIBRARIES}\" \"${LIBRARY_DIRS}\" \"${LDFLAGS_OTHER}\"
+ # COMMAND ${Python3_EXECUTABLE} ${sip_SIP_CONFIGURE} ${SIP_BUILD_DIR} ${SIP_FILE} ${sip_LIBRARY_DIR}
+ # \"${INCLUDE_DIRS}\" \"${LIBRARIES}\" \"${LIBRARY_DIRS}\" \"${LDFLAGS_OTHER}\"
+ COMMAND ${Python3_EXECUTABLE} -m sipbuild.tools.build --build-dir ${SIP_BUILD_DIR} --no-compile
DEPENDS ${sip_SIP_CONFIGURE} ${SIP_FILE} ${sip_DEPENDS}
WORKING_DIRECTORY ${sip_SOURCE_DIR}
COMMENT "Running SIP generator for ${PROJECT_NAME} Python bindings..."
diff --git a/package.xml b/package.xml
index 34703d6..7a454d2 100644
--- a/package.xml
+++ b/package.xml
@@ -28,7 +28,7 @@
ament_cmake
- qtbase5-dev
+ qt6-base-dev
python3-qt5-bindings
python3-qt5-bindings
@@ -36,7 +36,7 @@
ament_cmake_pytest
ament_lint_auto
ament_lint_common
-
+
ament_cmake
diff --git a/src/python_qt_binding/__init__.py b/src/python_qt_binding/__init__.py
index 1e209de..59a8769 100644
--- a/src/python_qt_binding/__init__.py
+++ b/src/python_qt_binding/__init__.py
@@ -58,6 +58,11 @@
from python_qt_binding.binding_helper import QT_BINDING_MODULES
from python_qt_binding.binding_helper import QT_BINDING_VERSION # noqa: F401
+print('QT_BINDING', QT_BINDING)
+for module, value in QT_BINDING_MODULES.items():
+ print('QT_BINDING_MODULES', module, value)
+print('QT_BINDING_VERSION', QT_BINDING_VERSION)
+
# register binding modules as sub modules of this package (python_qt_binding) for easy importing
for module_name, module in QT_BINDING_MODULES.items():
sys.modules[__name__ + '.' + module_name] = module
diff --git a/src/python_qt_binding/binding_helper.py b/src/python_qt_binding/binding_helper.py
index 27c3237..d5ff4be 100644
--- a/src/python_qt_binding/binding_helper.py
+++ b/src/python_qt_binding/binding_helper.py
@@ -51,10 +51,11 @@ def _select_qt_binding(binding_name=None, binding_order=None):
global QT_BINDING, QT_BINDING_VERSION
# order of default bindings can be changed here
- if platform.system() == 'Darwin':
- DEFAULT_BINDING_ORDER = ['pyside']
- else:
- DEFAULT_BINDING_ORDER = ['pyqt', 'pyside']
+ DEFAULT_BINDING_ORDER = ['pyside']
+ # if platform.system() == 'Darwin':
+ # DEFAULT_BINDING_ORDER = ['pyside']
+ # else:
+ # DEFAULT_BINDING_ORDER = ['pyside', 'pyqt']
binding_order = binding_order or DEFAULT_BINDING_ORDER
@@ -155,9 +156,9 @@ def _load_pyqt(required_modules, optional_modules):
# register required and optional PyQt modules
for module_name in required_modules:
- _named_import('PyQt5.%s' % module_name)
+ _named_import('PyQt6.%s' % module_name)
for module_name in optional_modules:
- _named_optional_import('PyQt5.%s' % module_name)
+ _named_optional_import('PyQt6.%s' % module_name)
# set some names for compatibility with PySide
sys.modules['QtCore'].Signal = sys.modules['QtCore'].pyqtSignal
@@ -166,19 +167,19 @@ def _load_pyqt(required_modules, optional_modules):
# try to register Qwt module
try:
- import PyQt5.Qwt5
- _register_binding_module('Qwt', PyQt5.Qwt5)
+ import PyQt6.Qwt6
+ _register_binding_module('Qwt', PyQt6.Qwt6)
except ImportError:
pass
global _loadUi
def _loadUi(uifile, baseinstance=None, custom_widgets_=None):
- from PyQt5 import uic
+ from PyQt6 import uic
return uic.loadUi(uifile, baseinstance=baseinstance)
- import PyQt5.QtCore
- return PyQt5.QtCore.PYQT_VERSION_STR
+ import PyQt6.QtCore
+ return PyQt6.QtCore.PYQT_VERSION_STR
def _load_pyside(required_modules, optional_modules):
@@ -187,9 +188,9 @@ def _load_pyside(required_modules, optional_modules):
# register required and optional PySide modules
for module_name in required_modules:
- _named_import('PySide2.%s' % module_name)
+ _named_import('PySide6.%s' % module_name)
for module_name in optional_modules:
- _named_optional_import('PySide2.%s' % module_name)
+ _named_optional_import('PySide6.%s' % module_name)
# set some names for compatibility with PyQt
sys.modules['QtCore'].pyqtSignal = sys.modules['QtCore'].Signal
@@ -206,8 +207,8 @@ def _load_pyside(required_modules, optional_modules):
global _loadUi
def _loadUi(uifile, baseinstance=None, custom_widgets=None):
- from PySide2.QtUiTools import QUiLoader
- from PySide2.QtCore import QMetaObject
+ from PySide6.QtUiTools import QUiLoader
+ from PySide6.QtCore import QMetaObject
class CustomUiLoader(QUiLoader):
class_aliases = {
@@ -253,8 +254,8 @@ def createWidget(self, class_name, parent=None, name=''):
QMetaObject.connectSlotsByName(ui)
return ui
- import PySide2
- return PySide2.__version__
+ import PySide6
+ return PySide6.__version__
def loadUi(uifile, baseinstance=None, custom_widgets=None):