[Dev] Providing compatibility libraries to reduce breakages (icu, poppler)

Denis 'GNUtoo' Carikli GNUtoo at cyberdimension.org
Tue May 5 17:37:44 GMT 2020


Hi,

Parabola uses packages from various upstream distributions (Arch Linux,
Arch Linux ARM, Arch Linux 32).

It only uses the packages that are compliant with FSF's FSDG
guidelines[1], and on top of that we also have our own packages in
various repositories (libre, pcr, etc).

So the issue is that when upstream packages are synchronized into
Parabola repositories, some of the times some libraries are updated in
a way that is incompatible with the previous version of the libraries,
and Parabola packages that were built against the older version of the
libraries don't work anymore.

Some of the libraries like icu and poppler are very often updated in
incompatible ways, and have frequent releases, so this problem is very
frequent.

First known status:
-------------------
So at first nothing was done to fix that, and after some upgrades,
packages like iceweasel became completely unusable because they would
only work with the old library that is now gone.

Practically speaking users needed to have a backup of the old packages
that weren't broken yet, and install them back. I don't know if it was
possible to downgrade without that, and in any case doing that without
having the backuped packages was probably not trivial.

At this point Parabola contributors needed to rush to rebuild packages
that weren't always easy to rebuild, while users (which also includes
Parabola contributors) had their packages broken.

First workaround attempt:
-------------------------
Then this was improved by making packages like iceweasel depend on
specific versions of icu and poppler.

Practically speaking, when new ICU and poppler were synchronized, users
couldn't upgrade their packages anymore without fighting the package
manager until Parabola contributors rebuilt all the packages that
depended on icu and poppler that users had installed.

The issue is that if users upgraded but then needed to install a package
that depended on the older icu and poppler, they couldn't.

Blocking upgrades for a long time is also not very convenient.

Many users were also wondering what was going on when they got the
error messages.

Second workaround attempt:
--------------------------
As I forgot that it was possible to depend on and provide specific
versions of libraries in packages, I rushed to implement a parabola
version of ICU in /opt as a proof of concept, to enable all Parabola
packages to link against it.

This way Arch packages would have depended on Arch icu while Parabola
packages would depended on Parabola icu. 

The main downside is that it's not very clean as we needed to modify
and rebuild all the Parabola packages to depend on Parabola ICU.

It also didn't work as intended as Arch Linux packages were using the
Parabola ICU when the versions were the same. The nice side effect is
that it consumed less RAM as only 1 ICU library would be used.

Third Workaround attempt:
-------------------------
The third attempt is more complicated but much more clean. We got a
lot of help from Eli Schwartz from Arch Linux to implement this
solution.

When the new icu library is synchronized, when users would upgrade their
packages, a new dependency (a package for an older version of ICU)
would be automatically pulled by packages not yet rebuilt against the
new ICU.

For that to work:
- We need Arch packages to use provides= in the packages
  providing libraries like icu. In the icu PKGBUILD we have the
  following:
  > provides=(libicu{data,i18n,io,test,tu,uc}.so)
- In Parabola packages depending on icu we need to replace the 'icu'
  dependency with the specific libraries. For instance in OpenTTD we
  have:
  > depends+=('libicui18n.so' 'libicuuc.so')
  Here, even if ldd /usr/bin/openttd shows libicudata.so as a
  dependency, it's not a direct dependency: it's pulled by libicuuc.so
  instead. It can be seen with readelf -d or lddtree from pax-utils.
  If useless dependencies are added, makepkg will warn about it:
  > WARNING: Library listed in 'depends' is not required by any files:
  > libicudata.so
  And it probably works fine with such dependencies as I didn't notice
  any issues with it so far.
- We need to provide a package for the older versions of ICU. This is
  currently done by the icu-parabola package (I'm not sure if the
  package name is very intuitive though).

So in practice on x86_64, inspecting the openttd package shows that we
have dependencies on very specific versions of libicuuc and libicui18n:
> $ pacman -Q -i openttd
>   [...]
>   Depends On: libpng sdl fontconfig lzo hicolor-icon-theme
>               desktop-file-utils xz fluidsynth libicui18n.so=67-64
>               libicuuc.so=67-64
>   [...]
At build time, the "depends+=('libicui18n.so' 'libicuuc.so')" expended
into the very specific libraries versions of libicui18n and libicuuc.
The -64 means that it's a 64bit library (here for x86_64).

The same also happened to icu for the Provides:
> $ pacman -Q -i icu
>   [...]
>   Provides: libicudata.so=67-64 libicui18n.so=67-64 libicuio.so=67-64
>             libicutest.so=67-64 libicutu.so=67-64 libicuuc.so=67-64
>   [...]

However having the provides is strictly required. For instance at the
time of writing, on i686, the new icu with provides is not synchronized
yet:
> $ pacman -Q -i icu
>   [...]
>   Provides: None
>   [...]

This means that we can't build openttd on i686 and we have to wait for
the new Arch Linux 32 package to be synchronized. The package is
in testing at the time of writing.

If we try to build it, as the icu-parabola package is the at the same
version than the icu that is already in i686 repositories, then both
icu and icu-parabola are pulled:
- icu is pulled as a dependency of libxml2
- icu-parabola is pulled because icu doesn't "Provide:" (yet) the 
  libicui18n.so and libicuuc.so libraries and only icu-parabola does.

And both icu and icu-parabola can't be installed at the same time here
because they have the same library version which is then installed in
the exact same location (for instance /usr/lib/libicudata.so.67).

So when using this scheme we need to make sure that all the
architectures have Provides for the library we're interested in using.

Usage, advantages and downsides of Third workaround:
----------------------------------------------------

Having two different versions of the same library consumes more space
and more RAM if both are used at the same time, so it's only meant to
enable Parabola contributors to get more time to rebuild packages for
the new libraries.

Without it we would need to have the build ready as soon as the new
libraries are synchronized. 

Assuming that we manage to get the builds ready in time (it would
be a good thing), for instance by watching arch PKGBUILD and testing
repository for libraries changes, it would still be a good idea to keep
this workaround.

First we might now always be able to recompile packages in time: The
compilation can be very long for some packages (recompiling iceweasel
requires 16G of RAM, so we need qemu to build it for ARM or to use
swap) and packages sometimes fails to build.

If we are not able to do that, then we would either have the same issue
again or move the issue to the feed synchronization where upgrades
would stop until all the rebuilds are done, which is not good either.

Denis.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 833 bytes
Desc: OpenPGP digital signature
URL: <https://lists.parabola.nu/pipermail/dev/attachments/20200505/7c3c504a/attachment-0001.sig>


More information about the Dev mailing list