diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2018-05-09 15:13:51 +0200 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2018-05-09 15:14:14 +0200 |
commit | 5fce76074c01e52a22151133a1e3a2cf71cfe535 (patch) | |
tree | 2d391fff868b398c1e2d77bd334f9a05b1d75394 | |
parent | 278c05bd61c69afe5ec3d30a56931aeadc17cae8 (diff) | |
parent | 9dc1aa57dfbf9c684e5c75451dd028b88099c348 (diff) |
Merge remote-tracking branch 'origin/5.9' into 5.11
Change-Id: Ic7aa7796dffda87ef492a99af7859c909ec607a2
25 files changed, 613 insertions, 231 deletions
diff --git a/build_scripts/main.py b/build_scripts/main.py index 23eb55008..fd5998480 100644 --- a/build_scripts/main.py +++ b/build_scripts/main.py @@ -1079,17 +1079,21 @@ class pyside_build(_build): if run_process(cmd_make) != 0: raise DistutilsSetupError("Error compiling {}".format(extension)) - if extension.lower() == "shiboken2": - try: - # Check if sphinx is installed to proceed. - import sphinx - - log.info("Generating Shiboken documentation") - if run_process([self.make_path, "doc"]) != 0: - raise DistutilsSetupError( - "Error generating documentation for {}".format(extension)) - except ImportError: - log.info("Sphinx not found, skipping documentation build") + if not OPTION_SKIP_DOCS: + if extension.lower() == "shiboken2": + try: + # Check if sphinx is installed to proceed. + import sphinx + + log.info("Generating Shiboken documentation") + if run_process([self.make_path, "doc"]) != 0: + raise DistutilsSetupError( + "Error generating documentation for {}".format( + extension)) + except ImportError: + log.info("Sphinx not found, skipping documentation build") + else: + log.info("Skipped documentation generation") if not OPTION_SKIP_MAKE_INSTALL: @@ -1184,8 +1188,8 @@ class pyside_build(_build): break if not clang_lib_path: - raise RuntimeError("Could not finding location of libclang " - "library from CMake cache.") + raise RuntimeError("Could not find the location of the libclang " + "library inside the CMake cache file.") if is_win: # clang_lib_path points to the static import library @@ -1193,27 +1197,26 @@ class pyside_build(_build): # library (bin/libclang.dll). clang_lib_path = re.sub(r'lib/libclang.lib$', 'bin/libclang.dll', clang_lib_path) + else: + # We want to resolve any symlink on Linux and macOS, and + # copy the actual file. + clang_lib_path = os.path.realpath(clang_lib_path) - # Path to directory containing clang. + # Path to directory containing libclang. clang_lib_dir = os.path.dirname(clang_lib_path) - # The name of the clang file found by CMake. - basename = os.path.basename(clang_lib_path) - - # We want to copy the library and all the symlinks for now, - # thus the wildcard. - clang_filter = basename + "*" - - # Destination is the package folder near the other extension - # modules. + # The destination will be the package folder near the other + # extension modules. destination_dir = "{}/PySide2".format(os.path.join(self.script_dir, 'pyside_package')) if os.path.exists(clang_lib_path): - log.info('Copying libclang shared library to the pyside package.') + log.info('Copying libclang shared library to the package folder.') + basename = os.path.basename(clang_lib_path) + destination_path = os.path.join(destination_dir, basename) - copydir(clang_lib_dir, destination_dir, - filter=[clang_filter], - recursive=False) + # Need to modify permissions in case file is not writable + # (a reinstall would cause a permission denied error). + copyfile(clang_lib_path, destination_path, make_writable_by_owner=True) else: raise RuntimeError("Error copying libclang library " "from {} to {}. ".format( diff --git a/build_scripts/options.py b/build_scripts/options.py index 3d02b368f..6472c664d 100644 --- a/build_scripts/options.py +++ b/build_scripts/options.py @@ -52,6 +52,8 @@ OPTION_ONLYPACKAGE = has_option("only-package") OPTION_STANDALONE = has_option("standalone") OPTION_MAKESPEC = option_value("make-spec") OPTION_IGNOREGIT = has_option("ignore-git") +# don't generate documentation +OPTION_SKIP_DOCS = has_option("skip-docs") # don't include pyside2-examples OPTION_NOEXAMPLES = has_option("no-examples") # number of parallel build jobs diff --git a/build_scripts/utils.py b/build_scripts/utils.py index db95df8a8..af40916b7 100644 --- a/build_scripts/utils.py +++ b/build_scripts/utils.py @@ -39,6 +39,7 @@ import sys import os +import stat import re import stat import errno @@ -274,7 +275,8 @@ def init_msvc_env(platform_arch, build_type): log.info("Done initializing MSVC env") -def copyfile(src, dst, force=True, vars=None, force_copy_symlink=False): +def copyfile(src, dst, force=True, vars=None, force_copy_symlink=False, + make_writable_by_owner=False): if vars is not None: src = src.format(**vars) dst = dst.format(**vars) @@ -287,6 +289,9 @@ def copyfile(src, dst, force=True, vars=None, force_copy_symlink=False): if not os.path.islink(src) or force_copy_symlink: log.info("Copying file {} to {}.".format(src, dst)) shutil.copy2(src, dst) + if make_writable_by_owner: + make_file_writable_by_owner(dst) + else: linkTargetPath = os.path.realpath(src) if os.path.dirname(linkTargetPath) == os.path.dirname(src): @@ -400,6 +405,9 @@ def copydir(src, dst, filter=None, ignore=None, force=True, recursive=True, raise EnvironmentError(errors) return results +def make_file_writable_by_owner(path): + current_permissions = stat.S_IMODE(os.lstat(path).st_mode) + os.chmod(path, current_permissions | stat.S_IWUSR) def rmtree(dirname): def handleRemoveReadonly(func, path, exc): diff --git a/examples/scriptableapplication/CMakeLists.txt b/examples/scriptableapplication/CMakeLists.txt index 368fd7d25..7e57a291b 100644 --- a/examples/scriptableapplication/CMakeLists.txt +++ b/examples/scriptableapplication/CMakeLists.txt @@ -28,7 +28,7 @@ macro(pyside2_config option output_var) OUTPUT_STRIP_TRAILING_WHITESPACE) if ("${${output_var}}" STREQUAL "") - message(FATAL_ERROR "Got empty string when running: pyside2_config.py ${option}") + message(FATAL_ERROR "Error: Calling pyside2_config.py ${option} returned no output.") endif() if(is_list) string (REPLACE " " ";" ${output_var} "${${output_var}}") @@ -43,10 +43,11 @@ if(NOT EXISTS ${SHIBOKEN_PATH}) message(FATAL_ERROR "Shiboken executable not found at path: ${SHIBOKEN_PATH}") endif() +pyside2_config(--pyside2 PYSIDE2_DIR) pyside2_config(--python-include PYTHON_INCLUDE_DIR) pyside2_config(--pyside2-include PYSIDE2_INCLUDE_DIR 1) -pyside2_config(--python-link-cmake PYTHON_LINKING_DATA 1) -pyside2_config(--pyside2-shared-libraries-cmake PYSIDE2_SHARED_LIBRARIES 1) +pyside2_config(--pyside2-shared-libraries-cmake PYSIDE2_SHARED_LIBRARIES 0) +pyside2_config(--python-link-cmake PYTHON_LINKING_DATA 0) # Get all relevant Qt include dirs, to pass them on to shiboken. get_property(QT_CORE_INCLUDE_DIRS TARGET Qt5::Core PROPERTY INTERFACE_INCLUDE_DIRECTORIES) @@ -120,8 +121,8 @@ endforeach() # ============================================================================================= # Enable rpaths so that the example can be executed from the build dir. set(CMAKE_SKIP_BUILD_RPATH FALSE) -set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) -SET(CMAKE_INSTALL_RPATH "") +set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) +set(CMAKE_INSTALL_RPATH ${PYSIDE2_DIR}) set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) # ============================================================================================= # !!! End of dubious section. @@ -148,7 +149,7 @@ target_link_libraries(${PROJECT_NAME} PRIVATE ${PYSIDE2_SHARED_LIBRARIES}) # Find and link to the python library. list(GET PYTHON_LINKING_DATA 0 PYTHON_LIBDIR) list(GET PYTHON_LINKING_DATA 1 PYTHON_LIB) -find_library(PYTHON_LINK_FLAGS ${PYTHON_LIB} HINTS ${PYTHON_LIBDIR}) +find_library(PYTHON_LINK_FLAGS ${PYTHON_LIB} PATHS ${PYTHON_LIBDIR} HINTS ${PYTHON_LIBDIR}) target_link_libraries(${PROJECT_NAME} PRIVATE ${PYTHON_LINK_FLAGS}) # Same as CONFIG += no_keywords to avoid syntax errors in object.h due to the usage of the word Slot diff --git a/examples/scriptableapplication/README.CMake.txt b/examples/scriptableapplication/README.CMake.txt deleted file mode 100644 index ea658efd5..000000000 --- a/examples/scriptableapplication/README.CMake.txt +++ /dev/null @@ -1,28 +0,0 @@ -For general information read README.txt instead. - -To build this example you will need: -* A recent version of CMake (3.1+) -* Make sure that a --standalone PySide2 package (bundled with Qt libraries) is installed into the - current active Python environment (system or virtualenv) -* qmake to be in your PATH (so that CMake find_package(Qt5) works; used for include headers) -* use the same Qt version for building the example application, as was used for building -* PySide2, this is to ensure binary compatibility between the newly generated bindings libraries, - the PySide2 libraries and the Qt libraries. - -For Windows you will also need: -* Visual studio environment to be active in your terminal -* Correct visual studio architecture chosen (32 vs 64 bit) -* Make sure that your Qt + Python + PySide + CMake app build configuration is the same (either or - all Release (which is more likely) or all Debug). - -You can build this example by executing the following commands (slightly adapted to your file -system) in a terminal: - -cd ~/pyside-setup/examples/scriptableapplication -(or cd C:\pyside-setup\examples\scriptableapplication) -mkdir build -cd build -cmake -H.. -B. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -(or cmake -H.. -B. -G "NMake Makefiles JOM" -DCMAKE_BUILD_TYPE=Release) -make (or nmake / jom) -./scriptableapplication (or scriptableapplication.exe) diff --git a/examples/scriptableapplication/README.md b/examples/scriptableapplication/README.md new file mode 100644 index 000000000..d359581f1 --- /dev/null +++ b/examples/scriptableapplication/README.md @@ -0,0 +1,170 @@ +# Scriptable Application + +This example demonstrates how to make a Qt C++ application scriptable. + +It has a class **MainWindow** (`mainwindow.{cpp,h}`) +that inherits from *QMainWindow*, for which bindings are generated +using Shiboken. + +The header `wrappedclasses.h` is passed to Shiboken which generates +class wrappers and headers in a sub directory called **AppLib/** +which are linked to the application. + +The files `pythonutils.{cpp,h}` contain some code which binds the +instance of **MainWindow** to a variable called **'mainWindow'** in +the global Python namespace (`__main___`). +It is then possible to run Python script snippets like: + +```python +mainWindow.testFunction1() +``` +which trigger the underlying C++ function. + +## Building the project + +This example can be built using *CMake* or *QMake*, +but there are common requirements that you need to take into +consideration: + +* Make sure that a --standalone PySide2 package (bundled with Qt libraries) + is installed into the current active Python environment + (system or virtualenv) +* qmake has to be in your PATH: + * so that CMake find_package(Qt5) works (used for include headers), + * used for building the application with qmake instead of CMake +* use the same Qt version for building the example application, as was used + for building PySide2, this is to ensure binary compatibility between the + newly generated bindings libraries, the PySide2 libraries and the + Qt libraries. + +For Windows you will also need: +* a Visual Studio environment to be active in your terminal +* Correct visual studio architecture chosen (32 vs 64 bit) +* Make sure that your Qt + Python + PySide2 package + app build configuration + is the same (all Release, which is more likely, or all Debug). +* Make sure that your Qt + Python + PySide2 package + app are built with the + same version of MSVC, to avoid mixing of C++ runtime libraries. + In principle this means that if you use the python.org provided Python + interpreters, you need to use MSVC2015 for Python 3 projects, and MSVC2008 + for Python 2 projects. Which also means that you can't use official Qt + packages, because none of the supported ones are built with MSVC2008. + +Both build options will use the `pyside2_config.py` file to configure the project +using the current PySide2/Shiboken2 installation (for qmake via pyside2.pri, +and for CMake via the project CMakeLists.txt). + + +### Using CMake + +To build this example with CMake you will need a recent version of CMake (3.1+). + +You can build this example by executing the following commands +(slightly adapted to your file system layout) in a terminal: + +On macOS/Linux: +```bash +cd ~/pyside-setup/examples/scriptableapplication +mkdir build +cd build +cmake -H.. -B. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release +make +./scriptableapplication +``` + +On Windows: +```bash +cd C:\pyside-setup\examples\scriptableapplication +mkdir build +cd build +cmake -H.. -B. -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release +# or if you have jom available +# cmake -H.. -B. -G "NMake Makefiles JOM" -DCMAKE_BUILD_TYPE=Release +nmake # or jom +scriptableapplication.exe +``` + +### Using QMake + +The file `scriptableapplication.pro` is the project file associated +to the example when using qmake. + +You can build this example by executing: +```bash +mkdir build +cd build +qmake .. +make # or nmake / jom for Windows +``` + +#### Windows troubleshooting + +Using **qmake** should work out of the box, there was a known issue +with directories and white spaces that is solved by using the +"~1" character, so the path will change from: +c:\Program Files\Python34\libs +to +c:\Progra~1\Python34\libs +this will avoid the issues when the Makefiles are generated. + +It is possible when using **cmake** to pick up the wrong compiler +for a different architecture, but it can be addressed explicitly +using the -G option: + +```bash +cmake -H.. -B. -G "Visual Studio 14 Win64" -DCMAKE_BUILD_TYPE=Release +``` + +If the `-G "Visual Studio 14 Win64"` option is used, a `sln` file +will be generated, and can be used with `MSBuild` +instead of `nmake/jom`. + +```bash +MSBuild scriptableapplication.sln "/p:Configuration=Release" +``` + +Note that using the "NMake Makefiles JOM" generator is preferred to +the MSBuild one, because in the latter case the executable is placed +into a directory other than the one that contains the dependency +dlls (shiboken, pyside). This leads to execution problems if the +application is started within the Release subdirectory and not the +one containing the dependencies. + +## Virtualenv Support + +If the application is started from a terminal with an activated python +virtual environment, that environment's packages will be used for the +python module import process. +In this case, make sure that the application was built while the +`virtualenv` was active, so that the build system picks up the correct +python shared library and PySide2 package. + +## Linux Shared Libraries Notes + +For this example's purpose, we link against the absolute paths of the +shared libraries (`libshiboken` and `libpyside`) because the +installation of the modules is being done via wheels, and there is +no clean solution to include symbolic links in the package +(so that regular -lshiboken works). + +## Windows Notes + +The build config of the application (Debug or Release) should match +the PySide2 build config, otherwise the application will not properly +work. + +In practice this means the only supported configurations are: + +1. release config build of the application + + PySide2 `setup.py` without `--debug` flag + `python.exe` for the + PySide2 build process + `python36.dll` for the linked in shared + library + release build of Qt. +2. debug config build of the application + + PySide2 `setup.py` **with** `--debug` flag + `python_d.exe` for the + PySide2 build process + `python36_d.dll` for the linked in shared + library + debug build of Qt. + +This is necessary because all the shared libraries in question have to +link to the same C++ runtime library (`msvcrt.dll` or `msvcrtd.dll`). +To make the example as self-contained as possible, the shared libraries +in use (`pyside2.dll`, `shiboken2.dll`) are hard-linked into the build +folder of the application. diff --git a/examples/scriptableapplication/README.txt b/examples/scriptableapplication/README.txt deleted file mode 100644 index 28bdb44ae..000000000 --- a/examples/scriptableapplication/README.txt +++ /dev/null @@ -1,33 +0,0 @@ -scriptableapplication demonstrates how to make a Qt C++ application scriptable. - -It has a class MainWindow inheriting QMainWindow for which bindings are generated -using PySide2's shiboken2 bindings generator. - -The header wrappedclasses.h is passed to shiboken2 which generates class -wrappers and headers in a subdirectory which are linked into the application. - -pythonutils.cpp has some code which binds the instance of MainWindow -to a variable 'mainWindow' in the global (__main___) namespace. -It is then possible to run Python script snippets like -mainWindow.testFunction1() which trigger the underlying C++ function. - -Virtualenv Support -If the application is started from a terminal with an activated python virtual environment, that -environment's packages will be used for the python module import process. In this case, make sure -that the application was built while the virtualenv was active, so that the build system picks up -the correct python shared library. - -Windows Notes -The build config of the application (Debug or Release) should match the PySide2 build config, -otherwise the application will not function correctly. In practice this means the only supported -configurations are: -1) qmake release config build of the application + PySide2 setup.py without "--debug" flag + - python.exe for the PySide2 build process + python36.dll for the linked in shared library + - release build of Qt. -2) qmake debug config build of the application + PySide2 setup.py WITH "--debug" flag + - python_d.exe for the PySide2 build process + python36_d.dll for the linked in shared library + - debug build of Qt. -This is necessary because all the shared libraries in question have to link to the same C++ runtime -library (msvcrt.dll or msvcrtd.dll). -To make the example as self-contained as possible, the shared libraries in use (pyside2.dll, -shiboken2.dll) are hard-linked into the build folder of the application. diff --git a/examples/scriptableapplication/pyside2.pri b/examples/scriptableapplication/pyside2.pri index bd0eeef9e..59f7fd983 100644 --- a/examples/scriptableapplication/pyside2.pri +++ b/examples/scriptableapplication/pyside2.pri @@ -1,16 +1,25 @@ +PYSIDE2 = $$system(python $$PWD/pyside2_config.py --pyside2) +isEmpty(PYSIDE2): error(Unable to locate the PySide2 package location) + PYTHON_INCLUDE = $$system(python $$PWD/pyside2_config.py --python-include) -isEmpty(PYTHON_INCLUDE): error(Unable to locate Python) +isEmpty(PYTHON_INCLUDE): error(Unable to locate the Python include headers directory) + PYTHON_LFLAGS = $$system(python $$PWD/pyside2_config.py --python-link) +isEmpty(PYTHON_LFLAGS): error(Unable to locate the Python library for linking) -PYSIDE2 = $$system(python $$PWD/pyside2_config.py --pyside2) -isEmpty(PYSIDE2): error(Unable to locate PySide2) PYSIDE2_INCLUDE = $$system(python $$PWD/pyside2_config.py --pyside2-include) +isEmpty(PYSIDE2_INCLUDE): error(Unable to locate the PySide2 include headers directory) + PYSIDE2_LFLAGS = $$system(python $$PWD/pyside2_config.py --pyside2-link) +isEmpty(PYSIDE2_LFLAGS): error(Unable to locate the PySide2 libraries for linking) + PYSIDE2_SHARED_LIBRARIES = $$system(python $$PWD/pyside2_config.py --pyside2-shared-libraries) -CLANG_BIN_DIR = $$system(python $$PWD/pyside2_config.py --clang-bin-dir) +isEmpty(PYSIDE2_SHARED_LIBRARIES): error(Unable to locate the used PySide2 shared libraries) -INCLUDEPATH += $$PYTHON_INCLUDE $$PYSIDE2_INCLUDE +INCLUDEPATH += "$$PYTHON_INCLUDE" $$PYSIDE2_INCLUDE LIBS += $$PYTHON_LFLAGS $$PYSIDE2_LFLAGS +!build_pass:message(INCLUDEPATH is $$INCLUDEPATH) +!build_pass:message(LIBS are $$LIBS) !build_pass:message(Using $$PYSIDE2) diff --git a/examples/scriptableapplication/pyside2_config.py b/examples/scriptableapplication/pyside2_config.py index a26d2b490..ce9c707c1 100644 --- a/examples/scriptableapplication/pyside2_config.py +++ b/examples/scriptableapplication/pyside2_config.py @@ -1,6 +1,6 @@ ############################################################################# ## -## Copyright (C) 2017 The Qt Company Ltd. +## Copyright (C) 2018 The Qt Company Ltd. ## Contact: http://www.qt.io/licensing/ ## ## This file is part of the Qt for Python examples of the Qt Toolkit. @@ -40,8 +40,6 @@ import os, glob, re, sys, imp from distutils import sysconfig -if sys.platform == 'win32': - import winreg usage = """ Utility to determine include/link options of PySide2 and Python for qmake @@ -54,7 +52,6 @@ Options: --pyside2-include Print PySide2 include paths --pyside2-link Print PySide2 link flags --pyside2-shared-libraries Print paths of PySide2 shared libraries (.so's, .dylib's, .dll's) - --clang-bin-dir Print path to the clang bin directory -a Print all --help/-h Print this help """ @@ -67,7 +64,9 @@ def sharedLibrarySuffix(): return 'lib' elif sys.platform == 'darwin': return 'dylib' - return 'so' + # Linux + else: + return 'so.*' def sharedLibraryGlobPattern(): glob = '*.' + sharedLibrarySuffix() @@ -84,12 +83,18 @@ def filterPySide2SharedLibraries(list): # Return qmake link option for a library file name def linkOption(lib): - baseName = os.path.splitext(os.path.basename(lib))[0] + # 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', 'darwin']: # Linux: 'libfoo.so' -> '-lfoo' - link += baseName[3:] - else: - link += baseName + 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 PySide2 via package path @@ -110,17 +115,27 @@ def pythonInclude(): def pythonLinkQmake(): flags = pythonLinkData() - if sys.platform == 'win32' or sys.platform == 'darwin': + 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") + return '-L{} -l{}'.format(libdir, flags['lib']) + elif sys.platform == 'darwin': return '-L{} -l{}'.format(flags['libdir'], flags['lib']) - # Linux and anything else - return '-l{}'.format(flags['lib']) + else: + # Linux and anything else + return '-L{} -l{}'.format(flags['libdir'], flags['lib']) def pythonLinkCmake(): flags = pythonLinkData() libdir = flags['libdir'] lib = re.sub(r'.dll$', '.lib', flags['lib']) - return '{} {}'.format(libdir, lib) + return '{};{}'.format(libdir, lib) def pythonLinkData(): # @TODO Fix to work with static builds of Python @@ -200,87 +215,71 @@ def pyside2SharedLibraries(): else: libs_string = '' for lib in libs: - libs_string += ' ' + lib + libs_string += lib + ' ' return libs_string def pyside2SharedLibrariesCmake(): libs = pyside2SharedLibrariesData() - result = ' '.join(libs) + result = ';'.join(libs) return result -def clangBinPath(): - source = 'LLVM_INSTALL_DIR' - clangDir = os.environ.get(source, None) - if not clangDir: - source = 'CLANG_INSTALL_DIR' - clangDir = os.environ.get(source, None) - if not clangDir: - source = 'llvm-config' - try: - output = run_process_output([source, '--prefix']) - if output: - clangDir = output[0] - except OSError: - pass - if clangDir: - return os.path.realpath(clangDir + os.path.sep + 'bin') - return '' - option = sys.argv[1] if len(sys.argv) == 2 else '-a' if option == '-h' or option == '--help': print(usage) sys.exit(0) +generic_error = (' Did you forget to activate your virtualenv? Or perhaps' + ' you forgot to build / install PySide2 into your currently active Python' + ' environment?') +pyside2_error = 'Unable to locate PySide2.' + generic_error +pyside2_libs_error = 'Unable to locate the PySide2 shared libraries.' + generic_error +python_link_error = 'Unable to locate the Python library for linking.' + if option == '--pyside2' or option == '-a': pySide2 = findPySide2() if pySide2 is None: - sys.exit('Unable to locate PySide2') + sys.exit(pyside2_error) print(pySide2) if option == '--pyside2-link' or option == '-a': l = pyside2Link() if l is None: - sys.exit('Unable to locate PySide2') + sys.exit(pyside2_error) + print(l) if option == '--pyside2-include' or option == '-a': i = pyside2Include() if i is None: - sys.exit('Unable to locate PySide2') + sys.exit(pyside2_error) print(i) if option == '--python-include' or option == '-a': i = pythonInclude() if i is None: - sys.exit('Unable to locate Python') + sys.exit('Unable to locate the Python include headers directory.') print(i) if option == '--python-link' or option == '-a': l = pythonLinkQmake() if l is None: - sys.exit('Unable to locate Python') + sys.exit(python_link_error) print(l) if option == '--python-link-cmake' or option == '-a': l = pythonLinkCmake() if l is None: - sys.exit('Unable to locate Python') + sys.exit(python_link_error) print(l) if option == '--pyside2-shared-libraries' or option == '-a': l = pyside2SharedLibraries() if l is None: - sys.exit('Unable to locate the PySide2 shared libraries') + sys.exit(pyside2_libs_error) print(l) if option == '--pyside2-shared-libraries-cmake' or option == '-a': l = pyside2SharedLibrariesCmake() if l is None: - sys.exit('Unable to locate the PySide2 shared libraries') - print(l) - -if option == '--clang-bin-dir' or option == '-a': - l = clangBinPath() - if l is None: - sys.exit('Unable to locate Clang') + sys.exit(pyside2_libs_error) print(l) diff --git a/examples/scriptableapplication/scriptableapplication.pro b/examples/scriptableapplication/scriptableapplication.pro index bcb05c115..8a09b0abf 100644 --- a/examples/scriptableapplication/scriptableapplication.pro +++ b/examples/scriptableapplication/scriptableapplication.pro @@ -9,8 +9,8 @@ WRAPPED_HEADER = wrappedclasses.h WRAPPER_DIR = $$OUT_PWD/AppLib TYPESYSTEM_FILE = scriptableapplication.xml -QT_INCLUDEPATHS = -I$$[QT_INSTALL_HEADERS] -I$$[QT_INSTALL_HEADERS]/QtCore \ - -I$$[QT_INSTALL_HEADERS]/QtGui -I$$[QT_INSTALL_HEADERS]/QtWidgets +QT_INCLUDEPATHS = -I"$$[QT_INSTALL_HEADERS]" -I"$$[QT_INSTALL_HEADERS]/QtCore" \ + -I"$$[QT_INSTALL_HEADERS]/QtGui" -I"$$[QT_INSTALL_HEADERS]/QtWidgets" # On macOS, check if Qt is a framework build. This affects how include paths should be handled. qtConfig(framework): QT_INCLUDEPATHS += --framework-include-paths=$$[QT_INSTALL_LIBS] @@ -24,15 +24,7 @@ win32:SHIBOKEN_OPTIONS += --avoid-protected-hack # Prepare the shiboken tool QT_TOOL.shiboken.binary = $$system_path($$PYSIDE2/shiboken2) -win32 { - # Add the libclang/bin subdir to PATH. - CLANG_PATH.name = PATH - CLANG_PATH.value = $$CLANG_BIN_DIR - CLANG_PATH.CONFIG += prepend - exists($$CLANG_PATH.value): QT_TOOL_ENV = CLANG_PATH -} qtPrepareTool(SHIBOKEN, shiboken) -QT_TOOL_ENV = # Shiboken run that adds the module wrapper to GENERATED_SOURCES shiboken.output = $$WRAPPER_DIR/applib_module_wrapper.cpp @@ -90,4 +82,4 @@ HEADERS += \ mainwindow.h \ pythonutils.h -OTHER_FILES += $$TYPESYSTEM_FILE $$WRAPPED_HEADER pyside2_config.py README.txt +OTHER_FILES += $$TYPESYSTEM_FILE $$WRAPPED_HEADER pyside2_config.py README.md diff --git a/missing_bindings.py b/missing_bindings.py index 11ff1334a..2d9267455 100644 --- a/missing_bindings.py +++ b/missing_bindings.py @@ -72,7 +72,6 @@ modules_to_test = OrderedDict() # Essentials modules_to_test['QtCore'] = 'qtcore-module.html' modules_to_test['QtGui'] = 'qtgui-module.html' -modules_to_test['QtWidgets'] = 'qtwidgets-module.html' modules_to_test['QtMultimedia'] = 'qtmultimedia-module.html' modules_to_test['QtMultimediaWidgets'] = 'qtmultimediawidgets-module.html' modules_to_test['QtNetwork'] = 'qtnetwork-module.html' @@ -80,23 +79,35 @@ modules_to_test['QtQml'] = 'qtqml-module.html' modules_to_test['QtQuick'] = 'qtquick-module.html' modules_to_test['QtSql'] = 'qtsql-module.html' modules_to_test['QtTest'] = 'qttest-module.html' +modules_to_test['QtWidgets'] = 'qtwidgets-module.html' # Addons +modules_to_test['Qt3DCore'] = 'qt3dcore-module.html' +modules_to_test['Qt3DInput'] = 'qt3dinput-module.html' +modules_to_test['Qt3DLogic'] = 'qt3dlogic-module.html' +modules_to_test['Qt3DRender'] = 'qt3drender-module.html' +modules_to_test['Qt3DAnimation'] = 'qt3danimation-module.html' +modules_to_test['Qt3DExtras'] = 'qt3dextras-module.html' modules_to_test['QtConcurrent'] = 'qtconcurrent-module.html' +modules_to_test['QtNetworkAuth'] = 'qtnetworkauth-module.html' modules_to_test['QtHelp'] = 'qthelp-module.html' -modules_to_test['QtOpenGL'] = 'qtopengl-module.html' modules_to_test['QtLocation'] = 'qtlocation-module.html' modules_to_test['QtPrintSupport'] = 'qtprintsupport-module.html' -modules_to_test['QtScript'] = 'qtscript-module.html' -modules_to_test['QtScriptTools'] = 'qtscripttools-module.html' +modules_to_test['QtSCXML'] = 'qtscxml-module.html' +modules_to_test['QtSpeech'] = 'qtspeech-module.html' modules_to_test['QtSvg'] = 'qtsvg-module.html' modules_to_test['QtUiTools'] = 'qtuitools-module.html' modules_to_test['QtWebChannel'] = 'qtwebchannel-module.html' +modules_to_test['QtWebEngine'] = 'qtwebengine-module.html' modules_to_test['QtWebEngineWidgets'] = 'qtwebenginewidgets-module.html' modules_to_test['QtWebSockets'] = 'qtwebsockets-module.html' +modules_to_test['QtMacExtras'] = 'qtmacextras-module.html' modules_to_test['QtX11Extras'] = 'qtx11extras-module.html' +modules_to_test['QtWinExtras'] = 'qtwinextras-module.html' modules_to_test['QtXml'] = 'qtxml-module.html' modules_to_test['QtXmlPatterns'] = 'qtxmlpatterns-module.html' +modules_to_test['QtCharts'] = 'qt-charts-module.html' +modules_to_test['QtDataVisualization'] = 'qtdatavisualization-module.html' types_to_ignore = set() # QtCore @@ -228,8 +239,8 @@ parser.add_argument("module", help="the Qt module for which to get the missing types") parser.add_argument("--qt-version", "-v", - default='5.6', - choices=['5.6', '5.8', '5.9', 'dev'], + default='5.11', + choices=['5.6', '5.9', '5.11', 'dev'], type=str, dest='version', help="the Qt version to use to check for types") @@ -129,6 +129,7 @@ using `setup.py build`: arguments, etc. --sanitize-address will build the project with address sanitizer enabled (Linux or macOS only). + --skip-docs skip the documentation generation. REQUIREMENTS: diff --git a/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml b/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml index 1e239f38b..77d074077 100644 --- a/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml +++ b/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml @@ -394,8 +394,9 @@ double in = %CONVERTTOCPP[double](%in); %out = %OUTTYPE(in); </add-conversion> - <add-conversion type="PyInt"> - int in = %CONVERTTOCPP[int](%in); + <!-- Using PyLong instead of PyInt to support Python2 and 3--> + <add-conversion type="PyInt" check="PyInt_CheckExact(%in)"> + qlonglong in = %CONVERTTOCPP[qlonglong](%in); %out = %OUTTYPE(in); </add-conversion> <add-conversion type="PyLong" check="PyLong_CheckExact(%in)"> diff --git a/sources/pyside2/PySide2/QtNetwork/CMakeLists.txt b/sources/pyside2/PySide2/QtNetwork/CMakeLists.txt index 68037017d..0267bfae3 100644 --- a/sources/pyside2/PySide2/QtNetwork/CMakeLists.txt +++ b/sources/pyside2/PySide2/QtNetwork/CMakeLists.txt @@ -4,18 +4,35 @@ set(QtNetwork_OPTIONAL_SRC ) set(QtNetwork_DROPPED_ENTRIES ) check_qt_class(QtNetwork QSslCertificate QtNetwork_OPTIONAL_SRC QtNetwork_DROPPED_ENTRIES) +check_qt_class(QtNetwork QSslCertificateExtension QtNetwork_OPTIONAL_SRC QtNetwork_DROPPED_ENTRIES) check_qt_class(QtNetwork QSslCipher QtNetwork_OPTIONAL_SRC QtNetwork_DROPPED_ENTRIES) check_qt_class(QtNetwork QSslConfiguration QtNetwork_OPTIONAL_SRC QtNetwork_DROPPED_ENTRIES) +check_qt_class(QtNetwork QSslDiffieHellmanParameters QtNetwork_OPTIONAL_SRC QtNetwork_DROPPED_ENTRIES) +# Problems with operator==(QSslEllipticCurve,QSslEllipticCurve) +# check_qt_class(QtNetwork QSslEllipticCurve QtNetwork_OPTIONAL_SRC QtNetwork_DROPPED_ENTRIES) check_qt_class(QtNetwork QSslError QtNetwork_OPTIONAL_SRC QtNetwork_DROPPED_ENTRIES) check_qt_class(QtNetwork QSslKey QtNetwork_OPTIONAL_SRC QtNetwork_DROPPED_ENTRIES) +check_qt_class(QtNetwork QSslPreSharedKeyAuthenticator QtNetwork_OPTIONAL_SRC QtNetwork_DROPPED_ENTRIES) check_qt_class(QtNetwork QSslSocket QtNetwork_OPTIONAL_SRC QtNetwork_DROPPED_ENTRIES) +check_qt_class(QtNetwork QSctpServer QtNetwork_OPTIONAL_SRC QtNetwork_DROPPED_ENTRIES) +check_qt_class(QtNetwork QSctpSocket QtNetwork_OPTIONAL_SRC QtNetwork_DROPPED_ENTRIES) + set(QtNetwork_SRC ${QtNetwork_GEN_DIR}/qabstractnetworkcache_wrapper.cpp ${QtNetwork_GEN_DIR}/qabstractsocket_wrapper.cpp ${QtNetwork_GEN_DIR}/qauthenticator_wrapper.cpp +${QtNetwork_GEN_DIR}/qdnsdomainnamerecord_wrapper.cpp +${QtNetwork_GEN_DIR}/qdnshostaddressrecord_wrapper.cpp +${QtNetwork_GEN_DIR}/qdnslookup_wrapper.cpp +${QtNetwork_GEN_DIR}/qdnsmailexchangerecord_wrapper.cpp +${QtNetwork_GEN_DIR}/qdnsservicerecord_wrapper.cpp +${QtNetwork_GEN_DIR}/qdnstextrecord_wrapper.cpp ${QtNetwork_GEN_DIR}/qhostaddress_wrapper.cpp ${QtNetwork_GEN_DIR}/qhostinfo_wrapper.cpp +${QtNetwork_GEN_DIR}/qhstspolicy_wrapper.cpp +${QtNetwork_GEN_DIR}/qhttpmultipart_wrapper.cpp +${QtNetwork_GEN_DIR}/qhttppart_wrapper.cpp ${QtNetwork_GEN_DIR}/qipv6address_wrapper.cpp ${QtNetwork_GEN_DIR}/qlocalserver_wrapper.cpp ${QtNetwork_GEN_DIR}/qlocalsocket_wrapper.cpp @@ -26,6 +43,7 @@ ${QtNetwork_GEN_DIR}/qnetworkconfiguration_wrapper.cpp ${QtNetwork_GEN_DIR}/qnetworkconfigurationmanager_wrapper.cpp ${QtNetwork_GEN_DIR}/qnetworkcookie_wrapper.cpp ${QtNetwork_GEN_DIR}/qnetworkcookiejar_wrapper.cpp +${QtNetwork_GEN_DIR}/qnetworkdatagram_wrapper.cpp ${QtNetwork_GEN_DIR}/qnetworkdiskcache_wrapper.cpp ${QtNetwork_GEN_DIR}/qnetworkinterface_wrapper.cpp ${QtNetwork_GEN_DIR}/qnetworkproxy_wrapper.cpp diff --git a/sources/pyside2/PySide2/QtNetwork/typesystem_network.xml b/sources/pyside2/PySide2/QtNetwork/typesystem_network.xml index 18c3b28bc..e4235e070 100644 --- a/sources/pyside2/PySide2/QtNetwork/typesystem_network.xml +++ b/sources/pyside2/PySide2/QtNetwork/typesystem_network.xml @@ -71,6 +71,22 @@ <modify-function signature="waitForDisconnected(int)" allow-thread="yes" /> </object-type> + <value-type name="QDnsDomainNameRecord"/> + <value-type name="QDnsHostAddressRecord"/> + <object-type name="QDnsLookup"> + <enum-type name="Error"/> + <enum-type name="Type"/> + </object-type> + <value-type name="QDnsMailExchangeRecord"/> + <value-type name="QDnsServiceRecord"/> + <value-type name="QDnsTextRecord"/> + <value-type name="QHstsPolicy" since="5.9"> + <enum-type name="PolicyFlag" flags="PolicyFlags"/> + </value-type> + <object-type name="QHttpMultiPart"> + <enum-type name="ContentType"/> + </object-type> + <value-type name="QHttpPart" since="5.9"/> <object-type name="QTcpServer"> <modify-function signature="waitForNewConnection(int,bool*)" allow-thread="yes"> <!-- FIXME removing default expression means user will always have to pass a value, but he wouldn't have to --> @@ -172,6 +188,7 @@ </modify-function> </object-type> <object-type name="QNetworkCookieJar"/> + <value-type name="QNetworkDatagram" since="5.8"/> <object-type name="QNetworkReply"> <enum-type name="NetworkError"/> </object-type> @@ -285,17 +302,30 @@ <object-type name="QNetworkDiskCache"/> <value-type name="QNetworkCacheMetaData"/> + <object-type name="QSctpServer"/> + <object-type name="QSctpSocket"/> + <!-- The following entries may be present in the system or not. Keep this section organized. --> <value-type name="QSslCertificate"> <enum-type name="SubjectInfo"/> </value-type> + <value-type name="QSslCertificateExtension"/> + <value-type name="QSslCipher"/> <value-type name="QSslConfiguration"> <enum-type name="NextProtocolNegotiationStatus" /> </value-type> + <value-type name="QSslDiffieHellmanParameters" since="5.8"> + <enum-type name="Error"/> + </value-type> + + <!-- Problems with operator==(QSslEllipticCurve,QSslEllipticCurve) + <object-type name="QSslEllipticCurve"/> + --> + <value-type name="QSslError"> <enum-type name="SslError"/> </value-type> @@ -307,6 +337,9 @@ <modify-function signature="connectToHostEncrypted(const QString&,quint16,QFlags<QIODevice::OpenModeFlag>,QAbstractSocket::NetworkLayerProtocol)" allow-thread="yes" /> <modify-function signature="waitForEncrypted(int)" allow-thread="yes" /> </object-type> + + <value-type name="QSslPreSharedKeyAuthenticator"/> + <!-- The above entries may be present in the system or not. Keep this section organized. --> </typesystem> diff --git a/sources/pyside2/doc/index.rst b/sources/pyside2/doc/index.rst index c8cd2fa79..90c95ade9 100644 --- a/sources/pyside2/doc/index.rst +++ b/sources/pyside2/doc/index.rst @@ -23,7 +23,7 @@ Qt Modules Provides classes for integrating online documentation in applications. * - `Qt Network <PySide2/QtNetwork/index.html>`_ Offers classes that lets you to write TCP/IP clients and servers. - - `Qt OpenGL <PySide2/QtCore/index.html>`_ + - `Qt OpenGL <PySide2/QtOpenGL/index.html>`_ Offers classes that make it easy to use OpenGL in Qt applications. * - `Qt PrintSupport <PySide2/QtPrintSupport/index.html>`_ Offers classes that make it easy to use OpenGL in Qt applications. diff --git a/sources/pyside2/tests/QtNetwork/CMakeLists.txt b/sources/pyside2/tests/QtNetwork/CMakeLists.txt index f93de5c17..c14c19fa9 100644 --- a/sources/pyside2/tests/QtNetwork/CMakeLists.txt +++ b/sources/pyside2/tests/QtNetwork/CMakeLists.txt @@ -1,6 +1,7 @@ PYSIDE_TEST(bug_446.py) PYSIDE_TEST(bug_1084.py) PYSIDE_TEST(accessManager_test.py) +PYSIDE_TEST(dnslookup_test.py) # Qt5: QHttp is gone PYSIDE_TEST(http_test.py) PYSIDE_TEST(tcpserver_test.py) PYSIDE_TEST(udpsocket_test.py) diff --git a/sources/pyside2/tests/QtNetwork/dnslookup_test.py b/sources/pyside2/tests/QtNetwork/dnslookup_test.py new file mode 100644 index 000000000..b0375b0f5 --- /dev/null +++ b/sources/pyside2/tests/QtNetwork/dnslookup_test.py @@ -0,0 +1,59 @@ +############################################################################# +## +## Copyright (C) 2018 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of Qt for Python. +## +## $QT_BEGIN_LICENSE:GPL-EXCEPT$ +## Commercial License Usage +## Licensees holding valid commercial Qt licenses may use this file in +## accordance with the commercial license agreement provided with the +## Software or, alternatively, in accordance with the terms contained in +## a written agreement between you and The Qt Company. For licensing terms +## and conditions see https://www.qt.io/terms-conditions. For further +## information use the contact form at https://www.qt.io/contact-us. +## +## GNU General Public License Usage +## Alternatively, this file may be used under the terms of the GNU +## General Public License version 3 as published by the Free Software +## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +## included in the packaging of this file. Please review the following +## information to ensure the GNU General Public License requirements will +## be met: https://www.gnu.org/licenses/gpl-3.0.html. +## +## $QT_END_LICENSE$ +## +############################################################################# + +'''Test cases for QDnsLookup''' + +import unittest + +from PySide2.QtCore import QCoreApplication +from PySide2.QtNetwork import QDnsLookup + +class DnsLookupTestCase(unittest.TestCase): + '''Test case for QDnsLookup''' + + def setUp(self): + self._app = QCoreApplication([]) + self._lookup = QDnsLookup(QDnsLookup.ANY, 'www.qt.io') + self._lookup.finished.connect(self._finished) + + def tearDown(self): + del self._lookup + + def _finished(self): + if self._lookup.error() == QDnsLookup.NoError: + nameRecords = self._lookup.canonicalNameRecords() + if nameRecords: + print(nameRecords[0].name()) + self._app.quit() + + def testLookup(self): + self._lookup.lookup() + self._app.exec_() + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside2/tests/registry/exists_darwin_5_9_4_ci.py b/sources/pyside2/tests/registry/exists_darwin_5_9_4_ci.py index 787ae0e80..95f3fe237 100644 --- a/sources/pyside2/tests/registry/exists_darwin_5_9_4_ci.py +++ b/sources/pyside2/tests/registry/exists_darwin_5_9_4_ci.py @@ -12558,12 +12558,12 @@ if "PySide2.QtNetwork" in sys.modules: "QNetworkAccessManager.head": ('PySide2.QtNetwork.QNetworkRequest',), "QNetworkAccessManager.isStrictTransportSecurityEnabled": (), "QNetworkAccessManager.networkAccessible": (), - "QNetworkAccessManager.post": [('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QByteArray'), ('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QIODevice')], + "QNetworkAccessManager.post": [('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QByteArray'), ('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QIODevice'), ('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtNetwork.QHttpMultiPart')], "QNetworkAccessManager.proxy": (), "QNetworkAccessManager.proxyFactory": (), - "QNetworkAccessManager.put": [('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QByteArray'), ('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QIODevice')], + "QNetworkAccessManager.put": [('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QByteArray'), ('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QIODevice'), ('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtNetwork.QHttpMultiPart')], "QNetworkAccessManager.redirectPolicy": (), - "QNetworkAccessManager.sendCustomRequest": [('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QByteArray', 'PySide2.QtCore.QByteArray'), ('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QByteArray', 'PySide2.QtCore.QIODevice')], + "QNetworkAccessManager.sendCustomRequest": [('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QByteArray', 'PySide2.QtCore.QByteArray'), ('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QByteArray', 'PySide2.QtCore.QIODevice'), ('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QByteArray', 'PySide2.QtNetwork.QHttpMultiPart')], "QNetworkAccessManager.setCache": ('PySide2.QtNetwork.QAbstractNetworkCache',), "QNetworkAccessManager.setConfiguration": ('PySide2.QtNetwork.QNetworkConfiguration',), "QNetworkAccessManager.setCookieJar": ('PySide2.QtNetwork.QNetworkCookieJar',), diff --git a/sources/pyside2/tests/registry/exists_linux_5_9_4_ci.py b/sources/pyside2/tests/registry/exists_linux_5_9_4_ci.py index 77ee0fdfa..79e826258 100644 --- a/sources/pyside2/tests/registry/exists_linux_5_9_4_ci.py +++ b/sources/pyside2/tests/registry/exists_linux_5_9_4_ci.py @@ -12555,12 +12555,12 @@ if "PySide2.QtNetwork" in sys.modules: "QNetworkAccessManager.head": ('PySide2.QtNetwork.QNetworkRequest',), "QNetworkAccessManager.isStrictTransportSecurityEnabled": (), "QNetworkAccessManager.networkAccessible": (), - "QNetworkAccessManager.post": [('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QByteArray'), ('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QIODevice')], + "QNetworkAccessManager.post": [('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QByteArray'), ('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QIODevice'), ('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtNetwork.QHttpMultiPart')], "QNetworkAccessManager.proxy": (), "QNetworkAccessManager.proxyFactory": (), - "QNetworkAccessManager.put": [('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QByteArray'), ('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QIODevice')], + "QNetworkAccessManager.put": [('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QByteArray'), ('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QIODevice'), ('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtNetwork.QHttpMultiPart')], "QNetworkAccessManager.redirectPolicy": (), - "QNetworkAccessManager.sendCustomRequest": [('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QByteArray', 'PySide2.QtCore.QByteArray'), ('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QByteArray', 'PySide2.QtCore.QIODevice')], + "QNetworkAccessManager.sendCustomRequest": [('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QByteArray', 'PySide2.QtCore.QByteArray'), ('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QByteArray', 'PySide2.QtCore.QIODevice'), ('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QByteArray', 'PySide2.QtNetwork.QHttpMultiPart')], "QNetworkAccessManager.setCache": ('PySide2.QtNetwork.QAbstractNetworkCache',), "QNetworkAccessManager.setConfiguration": ('PySide2.QtNetwork.QNetworkConfiguration',), "QNetworkAccessManager.setCookieJar": ('PySide2.QtNetwork.QNetworkCookieJar',), diff --git a/sources/pyside2/tests/registry/exists_win32_5_9_4_ci.py b/sources/pyside2/tests/registry/exists_win32_5_9_4_ci.py index 08f7ca897..20c30e1a3 100644 --- a/sources/pyside2/tests/registry/exists_win32_5_9_4_ci.py +++ b/sources/pyside2/tests/registry/exists_win32_5_9_4_ci.py @@ -12570,12 +12570,12 @@ if "PySide2.QtNetwork" in sys.modules: "QNetworkAccessManager.head": ('PySide2.QtNetwork.QNetworkRequest',), "QNetworkAccessManager.isStrictTransportSecurityEnabled": (), "QNetworkAccessManager.networkAccessible": (), - "QNetworkAccessManager.post": [('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QByteArray'), ('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QIODevice')], + "QNetworkAccessManager.post": [('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QByteArray'), ('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QIODevice'), ('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtNetwork.QHttpMultiPart')], "QNetworkAccessManager.proxy": (), "QNetworkAccessManager.proxyFactory": (), - "QNetworkAccessManager.put": [('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QByteArray'), ('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QIODevice')], + "QNetworkAccessManager.put": [('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QByteArray'), ('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QIODevice'), ('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtNetwork.QHttpMultiPart')], "QNetworkAccessManager.redirectPolicy": (), - "QNetworkAccessManager.sendCustomRequest": [('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QByteArray', 'PySide2.QtCore.QByteArray'), ('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QByteArray', 'PySide2.QtCore.QIODevice')], + "QNetworkAccessManager.sendCustomRequest": [('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QByteArray', 'PySide2.QtCore.QByteArray'), ('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QByteArray', 'PySide2.QtCore.QIODevice'), ('PySide2.QtNetwork.QNetworkRequest', 'PySide2.QtCore.QByteArray', 'PySide2.QtNetwork.QHttpMultiPart')], "QNetworkAccessManager.setCache": ('PySide2.QtNetwork.QAbstractNetworkCache',), "QNetworkAccessManager.setConfiguration": ('PySide2.QtNetwork.QNetworkConfiguration',), "QNetworkAccessManager.setCookieJar": ('PySide2.QtNetwork.QNetworkCookieJar',), diff --git a/sources/shiboken2/CMakeLists.txt b/sources/shiboken2/CMakeLists.txt index b65e32974..3efc6fefe 100644 --- a/sources/shiboken2/CMakeLists.txt +++ b/sources/shiboken2/CMakeLists.txt @@ -1,5 +1,6 @@ Include(icecc.cmake) project(shiboken2) +include(CheckIncludeFileCXX) cmake_minimum_required(VERSION 3.1) cmake_policy(VERSION 3.1) @@ -43,7 +44,7 @@ macro(get_llvm_config) import os import sys sys.path.append(os.path.realpath(os.path.join('${CMAKE_CURRENT_LIST_DIR}', '..', '..'))) - from utils import findLlvmConfig + from build_scripts.utils import findLlvmConfig llvmConfig = findLlvmConfig() if llvmConfig: print(llvmConfig) @@ -80,7 +81,7 @@ else () if (NOT "${CLANG_DIR}" STREQUAL "") EXEC_PROGRAM("${LLVM_CONFIG}" ARGS "--version" OUTPUT_VARIABLE CLANG_VERSION) if (CLANG_VERSION VERSION_LESS 3.9) - message(FATAL_ERROR "LLVM version 3.9 is required (${LLVM_CONFIG} detected ${CLANG_VERSION} at ${CLANG_DIR}).") + message(FATAL_ERROR "libclang version 3.9 or higher is required (${LLVM_CONFIG} detected ${CLANG_VERSION} at ${CLANG_DIR}).") endif() endif() endif() @@ -91,21 +92,39 @@ elseif (NOT IS_DIRECTORY ${CLANG_DIR}) message(FATAL_ERROR "${CLANG_DIR} detected by ${CLANG_DIR_SOURCE} does not exist.") endif() -set(CLANG_LIB_NAME "clang") +# The non-development Debian / Ubuntu packages (e.g. libclang1-6.0) do not ship a +# libclang.so symlink, but only libclang-6.0.so.1 and libclang.so.1 (adjusted for version number). +# Thus searching for libclang would not succeed. +# The "libclang.so" symlink is shipped as part of the development package (libclang-6.0-dev) which +# we need anyway because of the headers. Thus we will search for libclang.so.1 also, and complain +# about the headers not being found in a check further down. This is more friendly to the user, +# so they don't scratch their head thinking that they have already installed the necessary package. +set(CLANG_LIB_NAMES clang libclang.so libclang.so.1) if(MSVC) - set(CLANG_LIB_NAME "libclang") + set(CLANG_LIB_NAMES libclang) endif() -find_library(CLANG_LIBRARY ${CLANG_LIB_NAME} HINTS ${CLANG_DIR}/lib) +find_library(CLANG_LIBRARY NAMES ${CLANG_LIB_NAMES} HINTS ${CLANG_DIR}/lib) if (NOT EXISTS ${CLANG_LIBRARY}) - message(FATAL_ERROR "Unable to find Clang library ${CLANG_LIB_NAME} in ${CLANG_DIR}.") + string(REPLACE ";" ", " CLANG_LIB_NAMES_STRING "${CLANG_LIB_NAMES}") + message(FATAL_ERROR "Unable to find the Clang library in ${CLANG_DIR}.\ + Names tried: ${CLANG_LIB_NAMES_STRING}.") endif() message(STATUS "CLANG: ${CLANG_DIR}, ${CLANG_LIBRARY} detected by ${CLANG_DIR_SOURCE}") # Find highest version clang builtin includes folder to pass along to shiboken. set(CLANG_BUILTIN_INCLUDES_DIR_PREFIX ${CLANG_DIR}/lib/clang) -file(GLOB CLANG_BUILTIN_INCLUDES_DIR_VERSIONS "${CLANG_BUILTIN_INCLUDES_DIR_PREFIX}/*") +file(GLOB CLANG_BUILTIN_INCLUDES_DIR_CANDIDATES "${CLANG_BUILTIN_INCLUDES_DIR_PREFIX}/*") + +# Collect only directories, and not files, and only directories starting with a number. +set(CLANG_BUILTIN_INCLUDES_DIR_VERSIONS "") +foreach(candidate ${CLANG_BUILTIN_INCLUDES_DIR_CANDIDATES}) + get_filename_component(candidate_basename ${candidate} NAME) + if (IS_DIRECTORY ${candidate} AND ${candidate_basename} MATCHES "^[0-9]") # starts with number + list(APPEND CLANG_BUILTIN_INCLUDES_DIR_VERSIONS ${candidate}) + endif() +endforeach() # Sort in alphabetical order the list of version folders. list(SORT CLANG_BUILTIN_INCLUDES_DIR_VERSIONS) @@ -113,7 +132,9 @@ list(SORT CLANG_BUILTIN_INCLUDES_DIR_VERSIONS) # Reverse it so the first element is the highest version. list(REVERSE CLANG_BUILTIN_INCLUDES_DIR_VERSIONS) -message(STATUS "Found the following CLANG builtins includes directories: ${CLANG_BUILTIN_INCLUDES_DIR_VERSIONS}") +message(STATUS + "Found the following CLANG builtins includes directories: ${CLANG_BUILTIN_INCLUDES_DIR_VERSIONS} \ + Considered the following directories: ${CLANG_BUILTIN_INCLUDES_DIR_CANDIDATES}") if(CLANG_BUILTIN_INCLUDES_DIR_VERSIONS) # Get highest version. list(GET CLANG_BUILTIN_INCLUDES_DIR_VERSIONS 0 CLANG_BUILTIN_INCLUDES_DIR_HIGHEST_VERSION) @@ -122,11 +143,36 @@ if(CLANG_BUILTIN_INCLUDES_DIR_VERSIONS) set(CLANG_BUILTIN_INCLUDES_DIR "${CLANG_BUILTIN_INCLUDES_DIR_HIGHEST_VERSION}/include") endif() endif() + message(STATUS "CLANG builtins includes directory chosen: ${CLANG_BUILTIN_INCLUDES_DIR}") +# We don't exit with a hard error here, because it is uncertain whether all clang extra include +# paths follow the same layout across OSes and distros. +if (NOT CLANG_BUILTIN_INCLUDES_DIR) + message(WARNING "No CLANG builtins includes directory found. This may lead to shiboken \ + execution failure.") +endif() + set(CLANG_EXTRA_INCLUDES ${CLANG_DIR}/include) set(CLANG_EXTRA_LIBRARIES ${CLANG_LIBRARY}) +# Check if one of the required clang headers is found. Error out early at CMake time instead of +# compile time if not found. +# It can happen that a user uses a distro-provided libclang.so, but no development header package +# was installed (e.g. libclang-6.0-dev on Ubuntu). +set(CMAKE_REQUIRED_INCLUDES ${CLANG_EXTRA_INCLUDES}) +set(CLANG_HEADER_FILE_TO_CHECK "clang-c/Index.h") +check_include_file_cxx(${CLANG_HEADER_FILE_TO_CHECK} CLANG_INCLUDE_FOUND) +unset(CMAKE_REQUIRED_INCLUDES) +if (NOT CLANG_INCLUDE_FOUND) + # Need to unset so that when installing the package, CMake doesn't complain that the header + # still isn't found. + unset(CLANG_INCLUDE_FOUND CACHE) + message(FATAL_ERROR "Unable to find required Clang header file ${CLANG_HEADER_FILE_TO_CHECK} \ + in ${CLANG_DIR}/include. Perhaps you forgot to install the clang development header \ + package? (e.g. libclang-6.0-dev)") +endif() + set(SHIBOKEN_VERSION_FILE_PATH "${CMAKE_SOURCE_DIR}/shiboken_version.py") set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${SHIBOKEN_VERSION_FILE_PATH} diff --git a/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp index 98cdbf286..7206d7ca8 100644 --- a/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp +++ b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp @@ -230,6 +230,78 @@ static QString msgFallbackWarning(const QXmlStreamReader &reader, const QString return msgTagWarning(reader, context, tag, message); } +struct QtXmlToSphinx::LinkContext +{ + enum Type + { + Method = 0x1, Function = 0x2, + FunctionMask = Method | Function, + Class = 0x4, Attribute = 0x8, Module = 0x10, + Reference = 0x20, External= 0x40 + }; + + enum Flags { InsideBold = 0x1, InsideItalic = 0x2 }; + + explicit LinkContext(const QString &ref) : linkRef(ref) {} + + QString linkRef; + QString linkText; + Type type = Reference; + int flags = 0; +}; + +static const char *linkKeyWord(QtXmlToSphinx::LinkContext::Type type) +{ + switch (type) { + case QtXmlToSphinx::LinkContext::Method: + return ":meth:"; + case QtXmlToSphinx::LinkContext::Function: + return ":func:"; + case QtXmlToSphinx::LinkContext::Class: + return ":class:"; + case QtXmlToSphinx::LinkContext::Attribute: + return ":attr:"; + case QtXmlToSphinx::LinkContext::Module: + return ":mod:"; + case QtXmlToSphinx::LinkContext::Reference: + return ":ref:"; + case QtXmlToSphinx::LinkContext::External: + break; + } + return ""; +} + +QTextStream &operator<<(QTextStream &str, const QtXmlToSphinx::LinkContext &linkContext) +{ + // Temporarily turn off bold/italic since links do not work within + if (linkContext.flags & QtXmlToSphinx::LinkContext::InsideBold) + str << "**"; + else if (linkContext.flags & QtXmlToSphinx::LinkContext::InsideItalic) + str << '*'; + str << ' ' << linkKeyWord(linkContext.type) << '`'; + const bool isExternal = linkContext.type == QtXmlToSphinx::LinkContext::External; + if (!linkContext.linkText.isEmpty()) { + writeEscapedRstText(str, linkContext.linkText); + if (isExternal && !linkContext.linkText.endsWith(QLatin1Char(' '))) + str << ' '; + str << '<'; + } + // Convert page titles to RST labels + str << (linkContext.type == QtXmlToSphinx::LinkContext::Reference + ? toRstLabel(linkContext.linkRef) : linkContext.linkRef); + if (!linkContext.linkText.isEmpty()) + str << '>'; + str << '`'; + if (isExternal) + str << '_'; + str << ' '; + if (linkContext.flags & QtXmlToSphinx::LinkContext::InsideBold) + str << "**"; + else if (linkContext.flags & QtXmlToSphinx::LinkContext::InsideItalic) + str << '*'; + return str; +} + QtXmlToSphinx::QtXmlToSphinx(QtDocGenerator* generator, const QString& doc, const QString& context) : m_context(context), m_generator(generator), m_insideBold(false), m_insideItalic(false) { @@ -893,20 +965,15 @@ QtXmlToSphinx::LinkContext *QtXmlToSphinx::handleLinkStart(const QString &type, { ref.replace(QLatin1String("::"), QLatin1String(".")); ref.remove(QLatin1String("()")); - LinkContext *result = new LinkContext(toRstLabel(ref), type); - - result->linkTagEnding = QLatin1String("` "); - if (m_insideBold) { - result->linkTag.prepend(QLatin1String("**")); - result->linkTagEnding.append(QLatin1String("**")); - } else if (m_insideItalic) { - result->linkTag.prepend(QLatin1Char('*')); - result->linkTagEnding.append(QLatin1Char('*')); - } + LinkContext *result = new LinkContext(ref); + if (m_insideBold) + result->flags |= LinkContext::InsideBold; + else if (m_insideItalic) + result->flags |= LinkContext::InsideItalic; - if (result->type == functionLinkType() && !m_context.isEmpty()) { - result->linkTag = QLatin1String(" :meth:`"); + if (type == functionLinkType() && !m_context.isEmpty()) { + result->type = LinkContext::Method; const QVector<QStringRef> rawlinklist = result->linkRef.splitRef(QLatin1Char('.')); if (rawlinklist.size() == 1 || rawlinklist.constFirst() == m_context) { QString context = resolveContextForMethod(rawlinklist.constLast().toString()); @@ -915,10 +982,10 @@ QtXmlToSphinx::LinkContext *QtXmlToSphinx::handleLinkStart(const QString &type, } else { result->linkRef = expandFunction(result->linkRef); } - } else if (result->type == functionLinkType() && m_context.isEmpty()) { - result->linkTag = QLatin1String(" :func:`"); - } else if (result->type == classLinkType()) { - result->linkTag = QLatin1String(" :class:`"); + } else if (type == functionLinkType() && m_context.isEmpty()) { + result->type = LinkContext::Function; + } else if (type == classLinkType()) { + result->type = LinkContext::Class; if (const TypeEntry *type = TypeDatabase::instance()->findType(result->linkRef)) { result->linkRef = type->qualifiedTargetLangName(); } else { // fall back to the old heuristic if the type wasn't found. @@ -930,37 +997,64 @@ QtXmlToSphinx::LinkContext *QtXmlToSphinx::handleLinkStart(const QString &type, + QLatin1Char('.')); } } - } else if (result->type == QLatin1String("enum")) { - result->linkTag = QLatin1String(" :attr:`"); - } else if (result->type == QLatin1String("page") && result->linkRef == m_generator->moduleName()) { - result->linkTag = QLatin1String(" :mod:`"); + } else if (type == QLatin1String("enum")) { + result->type = LinkContext::Attribute; + } else if (type == QLatin1String("page")) { + // Module, external web page or reference + if (result->linkRef == m_generator->moduleName()) + result->type = LinkContext::Module; + else if (result->linkRef.startsWith(QLatin1String("http"))) + result->type = LinkContext::External; + else + result->type = LinkContext::Reference; } else { - result->linkTag = QLatin1String(" :ref:`"); + result->type = LinkContext::Reference; } return result; } -void QtXmlToSphinx::handleLinkText(LinkContext *linkContext, QString linktext) const +// <link raw="Model/View Classes" href="model-view-programming.html#model-view-classes" +// type="page" page="Model/View Programming">Model/View Classes</link> +// <link type="page" page="http://doc.qt.io/qt-5/class.html">QML types</link> +// <link raw="Qt Quick" href="qtquick-index.html" type="page" page="Qt Quick">Qt Quick</link> +// <link raw="QObject" href="qobject.html" type="class">QObject</link> +// <link raw="Qt::Window" href="qt.html#WindowType-enum" type="enum" enum="Qt::WindowType">Qt::Window</link> +// <link raw="QNetworkSession::reject()" href="qnetworksession.html#reject" type="function">QNetworkSession::reject()</link> + +static QString fixLinkText(const QtXmlToSphinx::LinkContext *linkContext, + QString linktext) { + if (linkContext->type == QtXmlToSphinx::LinkContext::External + || linkContext->type == QtXmlToSphinx::LinkContext::Reference) { + return linktext; + } + // For the language reference documentation, clear the link text if it matches + // the function/class/enumeration name. linktext.replace(QLatin1String("::"), QLatin1String(".")); + if (linkContext->linkRef == linktext) + return QString(); + if ((linkContext->type & QtXmlToSphinx::LinkContext::FunctionMask) != 0 + && (linkContext->linkRef + QLatin1String("()")) == linktext) { + return QString(); + } const QStringRef item = linkContext->linkRef.splitRef(QLatin1Char('.')).constLast(); - if (linkContext->linkRef == linktext - || (linkContext->linkRef + QLatin1String("()")) == linktext - || item == linktext - || (item + QLatin1String("()")) == linktext) { - linkContext->linkText.clear(); - } else { - linkContext->linkText = linktext + QLatin1Char('<'); + if (item == linktext) + return QString(); + if ((linkContext->type & QtXmlToSphinx::LinkContext::FunctionMask) != 0 + && (item + QLatin1String("()")) == linktext) { + return QString(); } + return linktext; +} + +void QtXmlToSphinx::handleLinkText(LinkContext *linkContext, const QString &linktext) const +{ + linkContext->linkText = fixLinkText(linkContext, linktext); } void QtXmlToSphinx::handleLinkEnd(LinkContext *linkContext) { - if (!linkContext->linkText.isEmpty()) - linkContext->linkTagEnding.prepend(QLatin1Char('>')); - m_output << linkContext->linkTag << linkContext->linkText; - writeEscapedRstText(m_output, linkContext->linkRef); - m_output << linkContext->linkTagEnding; + m_output << *linkContext; } // Copy images that are placed in a subdirectory "images" under the webxml files diff --git a/sources/shiboken2/generator/qtdoc/qtdocgenerator.h b/sources/shiboken2/generator/qtdoc/qtdocgenerator.h index d68eb1ea5..e467abe90 100644 --- a/sources/shiboken2/generator/qtdoc/qtdocgenerator.h +++ b/sources/shiboken2/generator/qtdoc/qtdocgenerator.h @@ -49,6 +49,8 @@ class QtDocGenerator; class QtXmlToSphinx { public: + struct LinkContext; + struct InlineImage { QString tag; @@ -114,17 +116,6 @@ public: } private: - struct LinkContext - { - LinkContext(const QString &ref, const QString &lType) : linkRef(ref), type(lType) {} - - QString linkTag; - QString linkRef; - QString linkText; - QString linkTagEnding; - QString type; - }; - QString resolveContextForMethod(const QString& methodName) const; QString expandFunction(const QString& function) const; QString transform(const QString& doc); @@ -161,7 +152,7 @@ private: void handleAnchorTag(QXmlStreamReader& reader); LinkContext *handleLinkStart(const QString &type, QString ref) const; - void handleLinkText(LinkContext *linkContext, QString linktext) const; + void handleLinkText(LinkContext *linkContext, const QString &linktext) const; void handleLinkEnd(LinkContext *linkContext); typedef void (QtXmlToSphinx::*TagHandler)(QXmlStreamReader&); diff --git a/sources/shiboken2/libshiboken/sbkpython.h b/sources/shiboken2/libshiboken/sbkpython.h index 57828f624..6d90f4086 100644 --- a/sources/shiboken2/libshiboken/sbkpython.h +++ b/sources/shiboken2/libshiboken/sbkpython.h @@ -48,6 +48,10 @@ #define PyInt_Type PyLong_Type #define PyInt_Check PyLong_Check + #define PyInt_CheckExact PyLong_CheckExact + #define PyInt_FromString PyLong_FromString + #define PyInt_FromSsize_t PyLong_FromSsize_t + #define PyInt_FromSize_t PyLong_FromSize_t #define PyInt_AS_LONG PyLong_AS_LONG #define PyInt_AsUnsignedLongLongMask PyLong_AsLongLong #define PyInt_FromLong PyLong_FromLong |