using sip-wheel on MacOS

Steve Borho steve at borho.org
Wed Apr 29 02:52:13 BST 2020



> On Apr 28, 2020, at 3:46 PM, Phil Thompson <phil at riverbankcomputing.com> wrote:
> 
> On 28/04/2020 18:49, Steve Borho wrote:
>>> On Apr 28, 2020, at 3:58 AM, Phil Thompson <phil at riverbankcomputing.com> wrote:
>>> On 28/04/2020 04:55, Steve Borho wrote:
>>>> Hello,
>>>> On Linux and Windows I can use sip-wheel to build binary wheels that
>>>> will gladly use the Qt libraries packaged by PyQt5, by compiling
>>>> against the same local version of Qt.
>>>> But when I try this on Mac, it is linking in the full paths to the
>>>> local (homebrew) Qt libraries
>>>> $ otool -L foo.cpython-37m-darwin.so
>>>> foo.cpython-37m-darwin.so:
>>>> 	/usr/local/opt/qt/lib/QtPrintSupport.framework/Versions/5/QtPrintSupport
>>>> (compatibility version 5.14.0, current version 5.14.1)
>>>> 	/usr/local/opt/qt/lib/QtOpenGL.framework/Versions/5/QtOpenGL
>>>> (compatibility version 5.14.0, current version 5.14.1)
>>>> 	/usr/local/opt/qt/lib/QtWidgets.framework/Versions/5/QtWidgets
>>>> (compatibility version 5.14.0, current version 5.14.1)
>>>> 	/usr/local/opt/qt/lib/QtDataVisualization.framework/Versions/5/QtDataVisualization
>>>> (compatibility version 5.14.0, current version 5.14.1)
>>>> 	/usr/local/opt/qt/lib/QtGui.framework/Versions/5/QtGui (compatibility
>>>> version 5.14.0, current version 5.14.1)
>>>> I see that sip-wheel has an option for:
>>>> --target-qt-dir DIR   the Qt libraries will be found in DIR when the wheel
>>>>                       is installed
>>>> but it is not clear how to target the PyQt5 packaged Qt libraries.
>>>> Has anyone else tackled this?  Thanks
>>> Assuming you are going to package a Qt installation with your wheel using pyqt-bundle at a later stage then pass '--target-qt-dir Qt/lib'.
>>> This will be documented in the next release of the PyQt docs.
>> Ideally the binaries in the wheel would use the Qt libraries in
>> ../PyQt5/Qt/lib/* from site-packages.
>> Does my app need to package its own copy of the Qt libraries if it
>> compiles its own shared library?
>> I just realized my Linux wheels have the same issue.  They are not
>> using PyQt5/Qt/lib, they are relying on the Qt libraries being present
>> where they were compiled.
> 
> I'm not sure what it is you are trying to achieve. The wheels on PyPI are created by running sip-wheel using the --target-qt-dir. The wheel is compiled against a local Qt installation but targeted for a bundled copy of Qt. That wheel, if installed, would not run. pyqt-bundle is then run to bundle a copy of that local Qt installation to create a new wheel (the one uploaded to PyPI).

I have a PyQt application which implements some plotters in C++ and we compile these into a shared library that links against several Qt libraries. sip creates the Python bindings for it

When the application is installed as a wheel, ideally the plotter shared library would link with the same Qt libraries that PyQt5 is using, under site-packages/PyQt5/Qt/lib.

Any Qt libraries I package with my application could possibly be incompatible with those that PyQt5 was compiled against and shipped with.  Is it typical for apps that use both PyQt5 from Python and the link to native Qt libraries to just ship the whole shebang (app + qt + pyqt) in one wheel?  I’m curious how this is generally solved.


I actually have this almost working by adding this bit of shenanigans to the main.py script:

import os
# relaunch the executable with site-packages/PyQt5/Qt/lib in library path
if 'APP_LIBPATH_HACK' not in os.environ:
    sitepackages = os.path.dirname(os.path.dirname(__file__))
    import sys
    if sys.platform in ('linux', 'darwin'):
        pyqt5 = os.path.join(sitepackages, 'PyQt5', 'Qt', 'lib')
    else:
        pyqt5 = os.path.join(sitepackages, 'PyQt5', 'Qt', 'bin')
    if os.path.isdir(pyqt5):
        if sys.platform == 'linux':
            os.environ['LD_LIBRARY_PATH'] = pyqt5
        elif sys.platform == 'darwin':
            os.environ['DYLD_FRAMEWORK_PATH'] = pyqt5
        else:
            os.environ['PATH'] = os.pathsep.join((pyqt5, os.environ['PATH']))
        os.environ['APP_LIBPATH_HACK'] = '1'
        os.execv(sys.argv[0], sys.argv)

It feels dirty, and doesn’t quite work because our plotter is linking against QtDataVisualization and this Qt library is not packaged with PyQt5, I presume because there are no Python bindings for it yet.  Is support for QtDataVisualization on the roadmap?

Thanks for the help,

Steve Borho


More information about the PyQt mailing list