What is best practice for RPM packaging something that provides a library which in name shadows a system library?
Background:
For an RPM-backed Linux system, I am packaging a "self-contained" app foo
that wants to live under /opt and supply as many of its own dependencies as it can, so as not to rely on the versions installed on the main system. (foo
uses LD_LIBRARY_PATH to avoid system libraries.)
Unfortunately, one of the foo
dependencies is a library grunk
, whose version is exactly that of the libgrunk.so
required for the main system. RPM's automatic Provides: generation then identifies two RPMs as providing this library. (That's not really true — only the system package makes the library available to any program whatsoever, whereas the foo
package makes it available only to foo
.)
This confounds automatic dependency resolution sometimes. For example, yum
might install the wrong package or only one package when two are needed.
Example:
grunk-libs-1.2-3.$arch.rpm # System Library
Files:
%{_libdir}/libgrunk.so.1
%{_libdir}/libgrunk.so.1.2
Provides:
libgrunk.so.1()(%{_arch})
foo-x.y.z-r.$arch.rpm # App
Files:
/opt/foo
/opt/foo/bin/...
Requires:
libgrunk.so.1()(%{_arch}) # foo needs grunk, but wants its own instance
foo-grunklibs-1.2-1.$arch.rpm # App Dependency
Files:
/opt/foo/libs/libgrunk.so.1
/opt/foo/libs/libgrunk.so.1.2
Provides:
libgrunk.so.1()(%{_arch}) # <-- same as from system "grunk-libs"
I've disabled AutoReqProv for now, but I want to be able to take advantage of RPM's automatic capabilities and dependency generation. I want RPM to know that foo.rpm
does require foo-grunklibs.rpm
by virtue of the latter's libgrunk.so.1
, but also know that the same library from the main system rpm won't suffice.
I think I'm at the limits of conventional use. Is there a packaging technique I can use here to resolve this?
After considering this for a while, I think the more correct approach is to use RPM virtual resource "namespaces". E.g.:
The RPMs end up looking like this:
In this way the
foo
dependency on the special build oflibgrunk
cannot be satisfied by the ordinarygrunk-libs
RPM, but must be satisfied by the foo-specific build of that library.My proof of concept looks like this:
Where the script find-namespaced-requires wraps the standard RPM %{_rpmconfigdir}/find-requires and filters its output. It's first argument is the namespace (
"foo(...)"
) to use, and subsequent arguments are dependencies or RPMs providing dependencies which should not be namespaced. In this example, I wantfoo
to require the main system's /bin/sh and also the ordinary libc, libdl, libm, etc. fromglibc
, but every other dependency should be assumed to be specific tofoo
.That could be made a little cleaner and more generic by wrapping up most of the above in a build-time RPM and saying something like: