Linker and Libraries Guide

Appendix C Recording Dependencies with $ORIGIN

Overview

The runtime linker has some flexibility to discover the pathnames of required dependencies. By default the runtime linker only knows to search in /usr/lib. This directory is normally augmented with recorded runpaths. These paths are recorded in an image at the time it was built, and commonly point to the standard installed location of any dependencies. This section will outline how runpaths can be augmented with the $ORIGIN token so that an application does not have to know its final install location when it is built at link-edit time.

Single Applications Use of $ORIGIN

Typically an unbundled product is designed to be installed in a standalone, unique location. This product is composed of binaries, shared object dependencies, and associated configuration files. For example, the unbundled product ABC might have the following layout:

Figure C-1 Unbundled Dependencies

Graphic

Let's assume that the product is designed for installation under /opt. Normally a user will be required to augment their PATH with /opt/ABC/bin so as to locate the product's binaries. Each binary will locate their dependencies using a hard-coded runpath within the binary. For the application abc it would be:


% dump -Lv abc
 
  [1]   NEEDED  libA.so.1
  [2]   RPATH   /opt/ABC/lib

and similarly for the dependency libA.so.1 this would be:


% dump -Lv libA.so.1
 
  [1]   NEEDED  libB.so.1
  [2]   RPATH   /opt/ABC/lib

This dependency representation works fine until the product is installed in some directory other than the recommended default. If a different installation is created, users must resort to LD_LIBRARY_PATH to run the product's applications. Often this is brought about by the introduction of wrappers for each binary, and sometimes inventive souls have even tried modifying the runpath within the appropriate objects.

Introducing $ORIGIN

$ORIGIN represents the directory in which an object originated. This feature keys off of a new auxiliary vector provided by the kernel to the runtime linker on process startup. Using this technology, we can now redefine our unbundled application to locate its dependencies in terms of $ORIGIN:


% dump -Lv abc
 
  [1]   NEEDED  libA.so.1
  [2]   RPATH   $ORIGIN/../lib

and the dependency libA.so.1 can also be defined in terms of $ORIGIN:


% dump -Lv libA.so.1
 
  [1]   NEEDED  libB.so.1
  [2]   RPATH   $ORIGIN

Therefore, if this product is now installed under /usr/local/ABC, and the user's PATH is augmented with /usr/local/ABC/bin of the application abc will result in a pathname lookup for its dependencies as follows:


% ldd -s abc
     find library=libA.so.1; required by abc
      search path=$ORIGIN/../lib  (RPATH from file abc)
      trying path=/usr/local/ABC/lib/libA.so.1
        libA.so.1 =>     /usr/local/ABC/lib/libA.so.1
 
     find library=libB.so.1; required by /usr/local/ABC/lib/libA.so.1
      search path=$ORIGIN  (RPATH from file /usr/local/ABC/lib/libA.so.1)
      trying path=/usr/local/ABC/lib/libB.so.1
        libB.so.1 =>     /usr/local/ABC/lib/libB.so.1

Dependencies Between Unbundled Products

The next issue to confront dependency location is how to establish a model whereby one unbundled product might have dependencies on the shared objects of another unbundled product.

For example, the unbundled product XYZ might have dependencies on the product ABC. This dependency can be established by a host package installation script that generates a symbolic link to the installation point of the ABC product:

Figure C-2 Unbundled Co-dependencies

Graphic

The binaries and shared objects of the XYZ product can represent their dependencies on the ABC product using the symbolic link as a stable reference point. For the application xyz this would be:


% dump -Lv xyz
  [1]   NEEDED  libX.so.1
  [2]   NEEDED  libA.so.1
  [3]   RPATH   $ORIGIN/../lib:$ORIGIN/../ABC/lib

and similarly for the dependency libX.so.1 this would be


% dump -Lv libX.so.1
  [1]   NEEDED  libY.so.1
  [2]   NEEDED  libC.so.1
  [3]   RPATH   $ORIGIN:$ORIGIN/../ABC/lib

Therefore, if this product is now installed under /usr/local/XYZ, its post-install script would be required to establish a symbolic link of:


% ln -s ../ABC /usr/local/XYZ/ABC

If the user's PATH is augmented with /usr/local/XYZ/bin, then invocation of the application xyz will result in a pathname lookup for its dependencies as follows:


% ldd -s xyz
     find library=libX.so.1; required by xyz
      search path=$ORIGIN/../lib:$ORIGIN/../ABC/lib  (RPATH from file xyz)
      trying path=/usr/local/XYZ/lib/libX.so.1
        libX.so.1 =>     /usr/local/XYZ/lib/libX.so.1
 
     find library=libA.so.1; required by xyz
      search path=$ORIGIN/../lib:$ORIGIN/../ABC/lib  (RPATH from file xyz)
      trying path=/usr/local/XYZ/lib/libA.so.1
      trying path=/usr/local/ABC/lib/libA.so.1
        libA.so.1 =>     /usr/local/ABC/lib/libA.so.1
 
     find library=libY.so.1; required by /usr/local/XYZ/lib/libX.so.1
      search path=$ORIGIN:$ORIGIN/../ABC/lib \
                (RPATH from file /usr/local/XYZ/lib/libX.so.1)
      trying path=/usr/local/XYZ/lib/libY.so.1
        libY.so.1 =>     /usr/local/XYZ/lib/libY.so.1
 
     find library=libC.so.1; required by /usr/local/XYZ/lib/libX.so.1
      search path=$ORIGIN:$ORIGIN/../ABC/lib \
                (RPATH from file /usr/local/XYZ/lib/libX.so.1)
      trying path=/usr/local/XYZ/lib/libC.so.1
      trying path=/usr/local/ABC/lib/libC.so.1
        libC.so.1 =>     /usr/local/ABC/lib/libC.so.1
 
     find library=libB.so.1; required by /usr/local/ABC/lib/libA.so.1
       search path=$ORIGIN  (RPATH from file /usr/local/ABC/lib/libA.so.1)
       trying path=/usr/local/ABC/lib/libB.so.1
        libB.so.1 =>     /usr/local/ABC/lib/libB.so.1