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