[bind10-dev] Libtool problem

Stephen Morris stephen at isc.org
Thu May 26 10:32:41 UTC 2011


On 12/05/2011 18:51, Francis Dupont wrote:
> strace to see what files are looked for?
> 
> Regards
> 
> Francis Dupont <fdupont at isc.org>
> 
> PS: usually ldd is enough but it is possible to have bad paths,
> strace is so basic it will show everything.
> PPS: if you don't find, send the system and the configure arguments:
> perhaps there is a VM available where I can reproduce the problem.

As Jelte has encountered the same problem regarding the need to link all
shared libraries into program images, I thought I'd share the results of
my investigations into the problem.  It's by no means solved, so any
solutions or explanations are welcome.

Stephen


Summary of Problem
==================
Although this is a general problem, I focused on one particular program:
the tests/tools/badpacket unit tests.  Amongst other libraries it is
linked against the BIND 10 utilities and exceptions libraries (libutil
and libexceptions).  It will run when the link command line includes
libexception but will fail to load when the libexceptions is omitted.
(The reason given is that it can't find this library.)  Since the
libutil library is explicitly linked against libexceptions, we would
expect the image activator to identify the dependency when it loads the
libutil and so load libexceptions.  This does not appear to happen.


Analysis
========

ldd output
----------
ldd prints the shared library dependencies of an image (or shared
library).  Running it libutil shows the dependency on libexceptions:

ldd ~/bind10-1/src/lib/util/.libs/libutil.so
	libexceptions.so.0 =>
/home/stephen/bind10-1/src/lib/exceptions/.libs/libexceptions.so.0

(Base addresses and unnecessary libraries removed from the output.)

Examination of the library dependencies of the unit tests program when
libexceptions is included at link time reveals:

ldd .libs/lt-run_unittests
	libexceptions.so.0 =>
/home/stephen/bind10-1/src/lib/exceptions/.libs/libexceptions.so.0
	libutil.so.0 => /home/stephen/bind10-1/src/lib/util/.libs/libutil.so.0

But if libexceptions is not explicitly linked in, the output is:

ldd .libs/lt-run_unittests
	libutil.so.0 => /home/stephen/bind10-1/src/lib/util/.libs/libutil.so.0
(0x003cf000)
	libexceptions.so.0 => not found
	libexceptions.so.0 =>
/home/stephen/bind10-1/src/lib/exceptions/.libs/libexceptions.so.0

For some reason, although the libexceptions dependency is found
(presumably through libutil), there appears to be something indicating
that libexceptions can't be located, even though there is also an entry
showing its location.

readelf
-------
Another view of this information can be found by using "readelf -d" to
look at the dynamic portion of the image. With libexceptions linked into
the image, the output is (as before, the output has been edited for
brevity):

% readelf -d .libs/lt-run_unittests
Shared library: [libexceptions.so.0]
Shared library: [libutil.so.0]
Library rpath: [/home/stephen/bind10-1/src/lib/exceptions/.libs:
                /home/stephen/bind10-1/src/lib/util/.libs:

/home/stephen/bind10-1/src/lib/util/unittests/.libs:/usr/lib]

Without libexceptions included at link time:

% readelf -d .libs/lt-run_unittests
Shared library: [libutil.so.0]
Shared library: [libexceptions.so.0]
Library rpath: [/home/stephen/bind10-1/src/lib/util/.libs:

/home/stephen/bind10-1/src/lib/util/unittests/.libs:/usr/lib]

So both libutil and libexecptions are included in the image dependencies
each time, but when libexceptions is included in the link, it's location
is in the image's rpath. ("rpath" is discussed below.)


LD_DEBUG
--------
Francis's suggestion of strace can be used to identify what libraries
are being opened, although setting the LD_DEBUG environment variable
produces output that is easier to interpret.  In particular, setting
LD_DEBUG to "files" causes the loader to output the library dependency
tree as it loads the image.

With libexceptions included in the link command line:

     16538:	file=libexceptions.so.0 [0];  needed by
.libs/lt-run_unittests [0]
       :
     16538:	file=libutil.so.0 [0];  needed by .libs/lt-run_unittests [0]
       :
     16538:	file=libutil_unittests.so.0 [0];  needed by
.libs/lt-run_unittests [0]
       :
     16538:	file=libutil_io.so.0 [0];  needed by

/home/stephen/bind10-1/src/lib/util/unittests/.libs/libutil_unittests.so.0
[0]

(The entries for libutil_unittests and libutil_io have been left in this
output because they indicate that the library dependency does work.
libutil_io was not included in the link but libutil_unittests was.  It
appears that libutil_io is being located through the rpath included in
libutil_unittests.)

Without libexceptions in the link:

     17419:	file=libutil.so.0 [0];  needed by .libs/lt-run_unittests [0]
       :
     17419:	file=libutil_unittests.so.0 [0];  needed by
.libs/lt-run_unittests [0]
       :
     17419:	file=libutil_unittests.so.0 [0];  generating link map
       :
     17419:	file=libexceptions.so.0 [0];  needed by
.libs/lt-run_unittests [0]
.libs/lt-run_unittests: error while loading shared libraries:
      libexceptions.so.0: cannot open shared object file: No such file
or directory

libexceptions is apparently required by the image directly instead of
being required by libutil.


Locating Shared Libraries
=========================
When the image is run, the problem the image activator has to overcome
is "where are the shared libraries?".  During the build, the program is
linked against libraries in the build directory.  However, when the
program, is installed, the libraries will be in a different place.  To
get round this, the image activator searches a number of locations for
the library.  According to http://www.eyrie.org/~eagle/notes/rpath.html
these are (in order):

* LD_LIBRARY_PATH (if set)
* "rpath" encoded in the binary
* System default search paths

The important element is the "rpath" encoded in the binary, which is set
in one of two ways:

* The setting of LD_RUN_PATH at link-time.
* The presence of "-R <location>" in the link command line  (This will
appear as "-Wl,-rpath, -Wl,<library>" in the automake command line.) If
any are present, they override the LD_RUN_PATH.

The binary loads shared libraries.  Since these can depend on other
shared libraries, there is an rpath encoded in the shared library as well.


Summary
=======
As the "ldd" and "readelf" output indicates, whether or not a particular
shared library is explicitly included in a link, the dependency on the
library will be included in the image if any of the libraries the image
links against depend on that shared library.

The problem then appears to be one of "rpath" - when the image is run,
the image loader is not able to locate the library in the path it is
searching.  However, this does not appear to be consistent: as the
LD_DEBUG output shows in the case of libutil_io, that library is able to
be found even though it does not appear explicitly in the link.

This, then, is the current state of investigation.  Any enlightenment is
welcome.


Addendum
========
The investigation cleared up the reason for an odd problem I had a
little while ago.  At that time I was in the habit of building BIND10
and specifying the --prefix when I ran configure (pointing to a local
directory).  That way, if I did a "make install" on any build, I
wouldn't have it in any of my system directories.

The odd problem I was having was that sometimes things would not run
properly.  Not always, just sometimes.  It took some effort to identify
the problem as having an old version of BIND 10 installed.  When that
was removed, everything worked.

I now think the reason for this is that when BIND 10 is built, the
installation directory is included in the rpath specified for images and
libraries at link time.  So when running some tests, the tests were
picking up (old) libraries in the installation directory instead of ones
in the build tree.



More information about the bind10-dev mailing list