Library versioning
Phil Thompson
phil at riverbankcomputing.com
Mon Mar 6 17:35:02 GMT 2023
On 04/03/2023 09:52, Jean Abou Samra wrote:
> Hi,
>
>
> I'm a bit confused regarding how wheels of libraries linking to Qt5
> should be built. Specifically, I am interested in
> [python-poppler-qt5](https://github.com/frescobaldi/python-poppler-qt5).
> The binding is built (with sip) on top of PyQt5, therefore I suppose
> it must link into Qt5 and PyQt5 libraries. This means that if I advise
> people to do "pip install python-poppler-qt5", it will download
> python-poppler-qt5 wheels built for one exact version of PyQt5, and
> other versions will not work due to ABI incompatibility. Right?
>
> So, how should this be done? Should the project specify a requirement
> "PyQt5 == specific-version"? Also, what ABI compatibility guarantees
> are provided on PyQt5? (I know Qt5 is guaranteed ABI-compatible within
> a minor release series.)
>
> As advised on
> [https://discuss.python.org/t/packaging-a-c-extension-with-a-dependency-on-another-c-extension/24462/2](https://discuss.python.org/t/packaging-a-c-extension-with-a-dependency-on-another-c-extension/24462/2),
> I looked briefly at how QScintilla does this, but I'm a bit confused.
> The project page says it's statically linked, yet on my system:
>
> ```
> $ ldd Qsci.abi3.so
> ldd: attention : vous n'avez pas la permission d'exécution pour
> `./Qsci.abi3.so'
> linux-vdso.so.1 (0x00007fff737e7000)
> libQt5PrintSupport.so.5 => /lib64/libQt5PrintSupport.so.5
> (0x00007f941df7e000)
> libQt5Widgets.so.5 => /lib64/libQt5Widgets.so.5 (0x00007f941d200000)
> libQt5Gui.so.5 => /lib64/libQt5Gui.so.5 (0x00007f941ca00000)
> libQt5Core.so.5 => /lib64/libQt5Core.so.5 (0x00007f941c400000)
> libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f941c000000)
> libm.so.6 => /lib64/libm.so.6 (0x00007f941d920000)
> libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f941df5c000)
> libc.so.6 => /lib64/libc.so.6 (0x00007f941be23000)
> libGL.so.1 => /lib64/libGL.so.1 (0x00007f941d179000)
> libpng16.so.16 => /lib64/libpng16.so.16 (0x00007f941df22000)
> libz.so.1 => /lib64/libz.so.1 (0x00007f941df08000)
> libharfbuzz.so.0 => /lib64/libharfbuzz.so.0 (0x00007f941d08d000)
> libsystemd.so.0 => /lib64/libsystemd.so.0 (0x00007f941c323000)
> libdouble-conversion.so.3 => /lib64/libdouble-conversion.so.3
> (0x00007f941d078000)
> libicui18n.so.71 => /lib64/libicui18n.so.71 (0x00007f941ba00000)
> libicuuc.so.71 => /lib64/libicuuc.so.71 (0x00007f941b803000)
> libpcre2-16.so.0 => /lib64/libpcre2-16.so.0 (0x00007f941c972000)
> libzstd.so.1 => /lib64/libzstd.so.1 (0x00007f941c26e000)
> libglib-2.0.so.0 => /lib64/libglib-2.0.so.0 (0x00007f941b6c2000)
> /lib64/ld-linux-x86-64.so.2 (0x00007f941e01a000)
> libGLX.so.0 => /lib64/libGLX.so.0 (0x00007f941d046000)
> libX11.so.6 => /lib64/libX11.so.6 (0x00007f941b57b000)
> libXext.so.6 => /lib64/libXext.so.6 (0x00007f941c259000)
> libGLdispatch.so.0 => /lib64/libGLdispatch.so.0 (0x00007f941bd6a000)
> libfreetype.so.6 => /lib64/libfreetype.so.6 (0x00007f941b4ad000)
> libgraphite2.so.3 => /lib64/libgraphite2.so.3 (0x00007f941c237000)
> libcap.so.2 => /lib64/libcap.so.2 (0x00007f941d916000)
> liblzma.so.5 => /lib64/liblzma.so.5 (0x00007f941bd36000)
> liblz4.so.1 => /lib64/liblz4.so.1 (0x00007f941b48a000)
> libicudata.so.71 => /lib64/libicudata.so.71 (0x00007f9419600000)
> libpcre2-8.so.0 => /lib64/libpcre2-8.so.0 (0x00007f941b3ed000)
> libxcb.so.1 => /lib64/libxcb.so.1 (0x00007f941b3c2000)
> libbz2.so.1 => /lib64/libbz2.so.1 (0x00007f941b3af000)
> libbrotlidec.so.1 => /lib64/libbrotlidec.so.1 (0x00007f941b3a2000)
> libXau.so.6 => /lib64/libXau.so.6 (0x00007f941d910000)
> libbrotlicommon.so.1 => /lib64/libbrotlicommon.so.1
> (0x00007f941b37f000)
> ```
>
> which looks like it links dynamically to several Qt5 libraries, though
> not to PyQt5's `*.abi3.so` libraries (is that what is meant by
> "statically linked"?).
>
> If I try to import it, I get
>
> ```
> $ python
> Python 3.11.2 (main, Feb 8 2023, 00:00:00) [GCC 12.2.1 20221121 (Red
> Hat 12.2.1-4)] on linux
> Type "help", "copyright", "credits" or "license" for more information.
>>>> import PyQt5.Qsci
> Traceback (most recent call last):
> File "<stdin>", line 1, in <module>
> ImportError:
> /home/jean/.local/lib/python3.11/site-packages/PyQt5/Qsci.abi3.so:
> undefined symbol: _ZdlPvm, version Qt_5
> ```
>
> because it's linking to Qt5 libs provided by my system. It works if I
> install qscintilla in a fresh venv, because pip then installs PyQt5 in
> the venv, with the latest PyPI version instead of my distro version.
> But if I downgrade qscintilla, it fails again, which I interpret as
> qscintilla really being built for one PyQt5 version and not being
> compatible with the next one. Yet, it seems to use "PyQt5 >= x.y"
> requirements, not "PyQt5 == x.y". Why?
>
> As you can see, I'm a beginner to this sort of stuff. If the questions
> seem dumb to you, I appreciate pointers to relevant resources.
>
> Thanks,
>
> Jean
With the current SIP implementation PyQt will guarantee ABI
compatibility for the same minor version number so in your case the
correct 'Requires-Dist' is "PyQt5 (>=5.15, <5.16)" to avoid potential
crashes.
The current PyQt sub-projects (Charts etc) don't do this and it is a
bug. However the pattern of releases and the way users upgrade means
this is rarely a problem (but I will fix it).
I am considering changing the SIP implementation so that it is the API
rather than the ABI that matters.
Phil
More information about the PyQt
mailing list