On Tue, Jan 13, 2026 at 12:59:31PM -0800, Gordon Messmer wrote:
> It's been a while since the last discussion of potential approaches to
> improving RPM's elfdeps:
> https://lists.fedorahosted.org/archives/list/[email protected]/thread/EZFX5ARQWOXBUXID4HH74ETD2QBF2DPB/#EZFX5ARQWOXBUXID4HH74ETD2QBF2DPB
>
> Since then, we continue to see occasional bug reports that rpm/dnf will
> install packages that fail at runtime because their binary dependencies are
> incomplete, in Fedora and in RHEL.
>
> ## The problem:
>
> The short version of the problem is that for libraries that do not provide
> versioned symbols (about 85% of libraries in Fedora, I think), rpm's
> "elfdeps" will generate a dependency expression that effectively provides
> only a major version.
>
> So, the libsoup3 rpm requires "libnghttp2.so.14()(64bit)" which is
> "libnghttp2.so, ABI version >= 14.0 and < 15", but the binary may depend on
> symbols that were introduced sometime after the original release of
> libnghttp2. The binary's dependency might be on ABI version >= 14.28, even
> if rpm's expression of that dependency only includes the major version
> (which is part of the soname).
>
> ## For example:
>
> If libnghttp2 is rebased during a Fedora release (or if the maintainers
> decide to introduce new symbols and bump the ABI minor version,
> mid-release), any binaries built after that could require the new ABI.
>
> So you might install from the installation media, and then:
>
> $ sudo dnf install chezdav
> $ chezdav
> chezdav: symbol lookup error: /lib64/libsoup-3.0.so.0: undefined symbol:
> nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation
>
> ## The solution:
>
> rpm's elfdeps should generate "Provides" and "Requires" that include at
> least a major and minor number. Those numbers could be the major and minor
> number of the DSO version ("libnghttp2.so.14.28.3" might result in providing
> "libnghttp2.so.14()(64bit) = 14.28") or they could be the version of the rpm
> in the build root ("libexpat.so.1.11.0" might result in providing
> "libexpat.so.1()(64bit) = 2.7.2"), or some other version source.
>
> Today, there are hundreds of packages that appear to be solving this problem
> by manually recording more specific dependency versions:
>
> rpm-specs]$ grep -r -E '^Requires:\s*lib.*>=' .| grep -v '{version}' | cut
> -f1 -d: | uniq | wc -l
> 267
>
> But in many cases, that requires developers to react to bug reports caused
> by runtime failures.
>
> ## Approaches to consider:
>
> We could use the DSO version, extracted from the symlink. In this case, the
> expat-2.7.3 package would provide "libexpat.so.1()(64bit) = 1.11.1" and any
> package that links to libexpat.so.1 would require "libexpat.so.1()(64bit) >=
> 1.11.1"
>
> One drawback to this approach is that a dependent binary package would
> require expat 2.7.3, even if they did not use any of the symbols that are
> new in that version, relative to expat-2.7.1. Some users might want to build
> on a system with expat-2.7.3 and deploy on a system with expat-2.7.1, as
> long as the binary is able to execute. Adding a more specific version to the
> requirement would result in dnf updating expat when the new binary is
> installed.
>
> Another potential drawback is that there are a few cases of interchangeable
> implementations of shared libraries in Fedora, and this would impose the
> additional requirement that anyone developing a library intended as an
> interoperable substitute would need to keep their DSO version in sync with
> the other implementations.
We don't need to boil the ocean. There are very few cases of interchangeable
impls. We could simply have a macro to disable the use of automatic versions
for those few packages, and then only concern ourselves with the common case.
> We could also do what Debian does, and require package maintainers to keep a
> symbol version map. In this case, after a build, the DSO can be analyzed for
> new symbols, and those symbols can be added to a file that lists the symbols
> exported by a shared library and the version in which they first appeared.
> That file needs to be kept in the package repo, and included in the -devel
> sub-package.
>
> I dislike that approach because it requires extra work from package
> maintainers, and because the symbol analysis has to be done post-build,
> which might mean doing another build to include the updated symbol map file.
>
> It's also nearly identical to the work required to simply add versioned
> symbols to shared libraries, which is a much better option, and doing the
> same amount of work to get a result that isn't as good doesn't make sense to
> me.
IMHO ELF symbol versioning is the best solution, but we should not be
maintaining that downstream.
Asking for that is effectively turning package maintainers into software
maintainers of an upstream fork, and IMHO that's beyond the bounds of
what I'd generally consider a downstream package maintainer responsibility.
If they wanted to be software maintainers, then they already have the
freedom to choose to engage in upstream. If they have done so, then they
could also propose adding symbol versioning. If they haven't done this,
we shouldn't ask them to do it downstream only.
Also there is a significant trap-door with sym versioning should a
maintainer ever cherry-pick a patch from a newer version that adds
a new API back to an old version.
If you keep the new version in the symbol file, then the RPM deps will
be a lie, as the package only supports 1 API from the new release, not
all APIs.
If you replace it with the old version in the symbol file, then the RPM
deps won't be protecting the upgrade path.
If you replace it with the old version, with an extra "point release"
digit appending, then you've protected the upgrade path, but anything
built against this old version with cherry-pick cannot now be loaded
against the subsequent release with the new symbol version, unless
you keep this duplicate symbol forever.
IMHO this leads to just a few practical approaches
- You *MUST* cherry-pick every single new API from a release,
never a subset of APIs, and keep the new version as the symbol
version
Or
- Simply rebase to the new version entirely
Or
- Never cherry-pick APIs to old releases.
Personally my recommendation is to never cherry-pick APIs under any
circumstances. If something is important enough to need the new
functionality in an existnig release then just rebase.
> abidb is a repository of ABI information generated and maintained by the
> libabigail project. A global DB of files, with symbols and the rpm version
> in which they first appeared could back a solution that is largely like
> Debian's approach, but without individual package maintainer overhead
If this magic is done behind the scenes and thus largely hidden from
package maintainers, how do we approach the problematic implications of
cherry-picking of new APIs to old versions ?
This is already somewhat of a surprising behaviour, for those small
set of packages where upstream has symbol versioning as standard, let
alone if we automatically extend this to every package in the distro.
With regards,
Daniel
--
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o- https://fstop138.berrange.com :|
|: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
--
_______________________________________________
devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]
Fedora Code of Conduct:
https://docs.fedoraproject.org/en-US/project/code-of-conduct/
List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines
List Archives:
https://lists.fedoraproject.org/archives/list/[email protected]
Do not reply to spam, report it:
https://pagure.io/fedora-infrastructure/new_issue