I'm finding a bunch of stuff where working packages contain files where ldd returns "not found" for some libraries. For example...

    libldap60.so => not found

    libjawt.so => not found

We have hundreds of users using Thunderbird and Libre Office, and no one has reported any problems. And these files exist on the system:


For this example, both /usr/bin/thunderbird and /usr/bin/libreoffice are wrapper scripts to launch the respective programs, and I expected that those scripts would set up the environment so that those libraries become visible, but it doesn't look like that happens in these scripts.

There are hundreds more examples of this throughout our system, I just chose these two as an example. Can anyone explain what's going on?


The direct (perhaps obvious) answer is that the search path for the libraries you are looking at with ldd does not include the directories where the library's own dependencies are located. Normally, unless a library's dependencies are found in system-wide standard locations, the library should have been built with a run path specified (by using the environment variable $LD_RUN_PATH or the appropriate linker option). Otherwise the libraries will not be found later on at run time, as you have found with ldd.

So why does Thunderbird work anyway despite this "problem"?

There are a few ways that the necessary libraries might be found anyway despite the missing run path:

  • The environment variable $LD_LIBRARY_PATH is set at run time and supplies a list of additional directories to search in.
  • The necessary directory might have gotten included into the search path because it was found in the run path of some other unrelated library that happened to be loaded prior the the current one. By the way, I'm not sure if this works as an accident of implementation of if the standard specifies it. One way or the other, it is fragile because it crucially depends on the exact order in which libraries are loaded.
  • The library might have been loaded manually by the application using the dlopen() function given a full pathname.

Thunderbird appears to be using the last of those techniques. I looked at strace output of what it does at startup and it seems to do this:

  • Locate the directory where its own binary comes from. This is always possible because the shell script helper that launches Thunderbird does so with a full pathname.
  • Open the text file dependentlibs.list found in that directory.
  • For each filename in this text file, in order, prepend the same directory to form a full path name, and load that as a library using dlopen().
  • Now all those dependent libraries like libldap60.so which you mentioned are "preloaded", and other libraries that require them don't need to find them again.

Notice that the order or the files listed in dependentlibs.list is significant.

The reason Thunderbird does this is so that the directory where it is located does not have to be hardcoded into either the application or into the run path of any of its internal libraries.

I don't know what Java does, but it is no doubt something similar.

  • 1
    Amazing. Thank you. We recently had an issue where a user discovered a legitimately broken package and brought it to our attention by showing with ldd that it was linking to non-existent files. The user was correct (it was relying on an undeclared dependency that no longer existed). So then I thought, "okay, so this doesn't happen again, I'm going to run ldd on everything after each system update, and anything that's 'not found' will show us where problems are." I see now, it's not that simple :) – CptSupermrkt Nov 11 '14 at 15:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.