diff options
-rw-r--r-- | examples/scriptableapplication/CMakeLists.txt | 8 | ||||
-rw-r--r-- | examples/scriptableapplication/README.CMake.txt | 28 | ||||
-rw-r--r-- | examples/scriptableapplication/README.md | 155 | ||||
-rw-r--r-- | examples/scriptableapplication/README.txt | 33 | ||||
-rw-r--r-- | examples/scriptableapplication/pyside2.pri | 6 | ||||
-rw-r--r-- | examples/scriptableapplication/pyside2_config.py | 39 | ||||
-rw-r--r-- | examples/scriptableapplication/scriptableapplication.pro | 4 |
7 files changed, 198 insertions, 75 deletions
diff --git a/examples/scriptableapplication/CMakeLists.txt b/examples/scriptableapplication/CMakeLists.txt index 368fd7d25..be5b17398 100644 --- a/examples/scriptableapplication/CMakeLists.txt +++ b/examples/scriptableapplication/CMakeLists.txt @@ -45,8 +45,12 @@ endif() 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) +if(WIN32) +pyside2_config(--python-link-cmake PYTHON_LINKING_DATA 0) +else() +pyside2_config(--python-link-cmake PYTHON_LINKING_DATA 1) +endif() # 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) @@ -148,7 +152,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} NO_DEFAULT_PATH) 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..98e12b7b4 --- /dev/null +++ b/examples/scriptableapplication/README.md @@ -0,0 +1,155 @@ +# 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}` contains 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 to be in your PATH: + * so that CMake find_package(Qt5) works (used for include headers), + * and also for using the proper qmake version when building with qmake +* 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 + app build configuration + is the same (either or all Release, which is more likely, or all Debug). + +Both build options will use the `pyside2.pri` file to configure the project +using the current PySide2/Shiboken2 installation (via `pyside2_config.py`). + +Keep in mind that Clang libraries must be on your path. + + +### 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) 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 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 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:DebugType=None" +``` + +## 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. + +## Shared Libraries Notes + +For this example's purpose, we are using the absolute path of the +shared libraries (`libshiboken` and `libpyside`) because the +installation of the modules is being made via wheels, and there is +no clean solution to include symbolic links into the package. + +## 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..acab9e961 100644 --- a/examples/scriptableapplication/pyside2.pri +++ b/examples/scriptableapplication/pyside2.pri @@ -9,8 +9,12 @@ PYSIDE2_LFLAGS = $$system(python $$PWD/pyside2_config.py --pyside2-link) PYSIDE2_SHARED_LIBRARIES = $$system(python $$PWD/pyside2_config.py --pyside2-shared-libraries) CLANG_BIN_DIR = $$system(python $$PWD/pyside2_config.py --clang-bin-dir) -INCLUDEPATH += $$PYTHON_INCLUDE $$PYSIDE2_INCLUDE +INCLUDEPATH += "$$PYTHON_INCLUDE" $$PYSIDE2_INCLUDE LIBS += $$PYTHON_LFLAGS $$PYSIDE2_LFLAGS +LIBPATH += $$PYTHON_LFLAGS $$PYSIDE2_LFLAGS +!build_pass:message(INCLUDEPATH is $$INCLUDEPATH) +!build_pass:message(LIBS are $$LIBS) +!build_pass:message(LIBPATH is $$LIBPATH) !build_pass:message(Using $$PYSIDE2) diff --git a/examples/scriptableapplication/pyside2_config.py b/examples/scriptableapplication/pyside2_config.py index a26d2b490..781c30b64 100644 --- a/examples/scriptableapplication/pyside2_config.py +++ b/examples/scriptableapplication/pyside2_config.py @@ -67,7 +67,9 @@ def sharedLibrarySuffix(): return 'lib' elif sys.platform == 'darwin': return 'dylib' - return 'so' + # Linux + else: + return 'so.*' def sharedLibraryGlobPattern(): glob = '*.' + sharedLibrarySuffix() @@ -84,12 +86,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:] + if sys.platform in ['linux', 'linux2']: # Linux: 'libfoo.so' -> '-lfoo' + link = lib + elif sys.platform in ['darwin']: # Linux: 'libfoo.so' -> '-lfoo' + link += os.path.splitext(baseName[3:])[0] else: - link += baseName + link += os.path.splitext(baseName)[0] return link # Locate PySide2 via package path @@ -110,17 +118,30 @@ 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) + if sys.platform == 'win32': + return '{};{}'.format(libdir, lib) + else: + return '{} {}'.format(libdir, lib) def pythonLinkData(): # @TODO Fix to work with static builds of Python diff --git a/examples/scriptableapplication/scriptableapplication.pro b/examples/scriptableapplication/scriptableapplication.pro index bcb05c115..ee96afde0 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] |