DT_RUNPATH settings for all libraries
John Moser
john.r.moser at gmail.com
Fri Jan 17 02:01:12 UTC 2014
Can we move to a DT_RUNPATH scheme for all libraries as below?
COMPATIBILITY
This change alone does almost nothing: with the system files arranged
as they are now, there is no change in how linking works.
ADVANTAGE
This change allows us to switch around libraries and to use different
versions of the same library. This allows for increased compatibility.
For example: every version of libfoo.so.2 should be
compatible--libfoo.so.2.15 should link properly with a program compiled
for libfoo.so.2.0. On occasion and for various reasons, this sometimes
doesn't happen; it become useful to have different versions of the same
library installed, yet they conflict. We have conflicting lib* packages.
DESCRIPTION
On load, ld.so links dynamic libraries in the following order:
1. DT_RPATH if DT_RUNPATH does not exist
2. LD_LIBRARY_PATH environment if not SUID/SGID
3. DT_RUNPATH
4. ld.so.cache file from ldconfig
5. /lib and then /usr/lib
This means that a binary (a main executable file, including a shared
object that may execute as a main executable file) specifying dynamic
linking to libfoo.so.2 will currently link against the first one of the
below:
1. $LD_LIBRARY_PATH/libfoo.so.2
2. The library specified in ld.so.cache
3. /lib/libfoo.so.2
4. /usr/lib/libfoo.so.2
A binary with DT_RPATH set will pre-empt $LD_LIBRARY_PATH, which breaks
that entire functionality. We don't want that.
A binary with DT_RUNPATH set will insert a new step. If DT_RUNPATH
contains "/var/lib/cat1:/var/lib/cat2" then the above checks the
following instead:
1. $LD_LIBRARY_PATH/libfoo.so.2
2. /var/lib/cat1/libfoo.so.2
3. /var/lib/cat2/libfoo.so.2
4. The library specified in ld.so.cache
5. /lib/libfoo.so.2
6. /usr/lib/libfoo.so.2
In this way, placing a different library at (2) or (3), or a symlink to
such, will cause that library to load instead.
PROPOSAL
Section 5.1 of the Filesystem Hierarchy Standard v2.2 ends in the
following stipulation:
Applications must generally not add directories to the top level
of /var. Such directories should only be added if they have some
system-wide implication, and in consultation with the FHS mailing
list.
I have investigated /var/lib, /var/cache, and /var/run and determined
that none of these is particularly suitable for this proposal. /var/lib
looks close; however, the system is managing these contents without
concern for what the application expects to see there. /var/run is for
the system state since boot, not persistent. /var/cache is just the
wrong application.
Leveraging the above, I propose that the DT_RUNPATH of each application
be set as follows:
/var/sys/$PACKAGE/lib:/var/sys/current-system/lib
For x86_64:
/var/sys/$PACKAGE/lib64:/var/sys/current-system/lib64
In the future, it may become possible to install conflicting libraries
to support binaries mutually non-conflicting save for dependencies on
conflicting libraries. To do so, a symlink to the conflicting library
wold be installed in the proper /var/sys/$PACKAGE/lib[64] directory.
The ability to do this depends on this proposal. It also depends on
rewiring dpkg and apt to recognize and manage conflicts as alternatives,
or to package conflicting libraries as alternatives and improve the
dpkg-alternatives system to recognize when the majority of installed
packages in a system rely on package X and a minority rely on package Y.
After all, somehow you need to decide which is "the main package" and
which is "installed for compatibility", and for what, and how to handle
that.
The change proposed is harmless, non-standards-breaking, and compatible
with Debian, Ubuntu, Mint, and ELF-based distributions in general. It
is heavily influenced by NixOS, although the particular mechanism comes
from a side project I never got started much (I don't like how NixOS
does it). It is expandable to achieve similar goals to NixOS by setting
DT_RUNPATH to:
/var/sys/$PACKAGE/$VERSION/lib:/var/sys/$PACKAGE/default/lib:/var/sys/current-system/lib
('default' is of course a misnomer; it's not straight 'lib' because you
may also mess with $PATH and put a bin and sbin in there, but that's a
big stretch)
Other ways to achieve the main goals of NixOS--running i.e. postgresql 7
8 9 and 10 at the same time--would be to use lxc, which is probably the
right way to do that. Between that and other factors, I haven't
proposed that.
Thoughts?
More information about the Ubuntu-devel-discuss
mailing list