What is the difference between LD_LIBRARY_PATH and

2019-01-21 11:31发布

问题:

I'm having problems with LD_LIBRARY_PATH at link time (this question has nothing to do with run time).

The link line looks like this when I run make (this is a Linux system using g++ version 4.1.x):

g++ a.o b.o c.o -o myapp \
 -L/long/path/to/libs/ \
 -L/another/long/path/ \
 -labc -ldef -lghi

The -l options reference shared libraries (e.g., libabc.so) which exist in the directories specified by the -L options. Those directories also appear in LD_LIBRARY_PATH. With that configuration, the link is successful, and I can run the application.

If I remove the directories from LD_LIBRARY_PATH, then I get a single error line such as:

/usr/bin/ld: cannot find -labc

On the other hand, if I remove the directories from the list of -L options, then I get many warnings such as:

/usr/bin/ld: warning: libabc.so, needed by /long/path/to/libs/libxyz.so,
    not found (try using -rpath or -rpath-link)

and then many more errors, such as:

/long/path/to/libs/libdef.so: undefined reference to `Foo::Bar<Baz>::junk(Fred*)'

Can someone explain the difference between LD_LIBRARY_PATH and -L? I would like to understand this stuff in depth, so references are greatly appreciated!

Also, what do I have to add to the link line to avoid using LD_LIBRARY_PATH?

EDIT: When directories were missing from -L, the compiler suggested to "try using -rpath or -rpath-link". I don't think I've ever seen those options in a makefile before. Have you? Not sure if that would help the LD_LIBRARY_PATH problem though.

回答1:

The settings of LD_LIBRARY_PATH has the highest precedence, so when it is set, the set of directories mentioned by LD_LIBRARY_PATH are searched first even before the standard set
of directories. So in your case setting of LD_LIBRARY_PATH is influencing the lookup of
the libraries mentioned with -l option. Without LD_LIBRARY_PATH some of the dependencies
might have been resolved from the standard set of directories.

Though setting of LD_LIBRARY_PATH help with debugging and to try out a newer version of
a library its usage in the general development environment setup and deployment is considered bad.

Also refer this HOWTO from Linux Documentation for more details on Shared Libraries



回答2:

There are two answers to this question, part of the answer lies in the compile-time linking (i.e gcc -lfoo -L/usr/lib ... which in turn calls ld), and run-time linker lookups.

When you compile your program, the compiler checks syntax, and then the linker ensures that the symbols required for execution exist (i.e variables / methods / etc), among other things. LD_LIBRARY_PATH, as has been noted, has the side-effect of altering the way gcc/ld behave as well as the way the the run-time linker behaves by modifying the search path.

When you run your program, the run-time linker actually fetches the shared libraries (on disk or from memory if possible), and loads in the shared symbols / code / etc. Again, LD_LIBRARY_PATH affects this search path implicitly (sometimes not a good thing, as has been mentioned.)

The correct fix for this without using LD_LIBRARY_PATH on most Linux systems is to add the path that contains your shared libraries to /etc/ld.so.conf (or in some distributions, create a file in /etc/ld.so.conf.d/ with the path in it) and run ldconfig (/sbin/ldconfig as root) to update the runtime linker bindings cache.

Example on Debian:

jewart@dorfl:~$ cat /etc/ld.so.conf.d/usrlocal.conf 
/usr/local/lib

Then when the program is executed, the run-time linker will look in those directories for libraries that your binary has been linked against.

If you want to know what libraries the run-time linker knows about, you can use:

jewart@dorfl:~$ ldconfig -v 

/usr/lib:
libbfd-2.18.0.20080103.so -> libbfd-2.18.0.20080103.so
libkdb5.so.4 -> libkdb5.so.4.0
libXext.so.6 -> libXext.so.6.4.0

And, if you want to know what libraries a binary is linked against, you can use ldd like such, which will tell you which library your runtime linker is going to choose:

jewart@dorfl:~$ ldd /bin/ls
linux-vdso.so.1 =>  (0x00007fffda1ff000)
librt.so.1 => /lib/librt.so.1 (0x00007f5d2149b000)
libselinux.so.1 => /lib/libselinux.so.1 (0x00007f5d2127f000)
libacl.so.1 => /lib/libacl.so.1 (0x00007f5d21077000)
libc.so.6 => /lib/libc.so.6 (0x00007f5d20d23000)


回答3:

LD_LIBRARY_PATH is intended for finding shared libraries when running an application. It is a side effect that it's impacting your link, and you should not rely on that.

As an often unwanted side effect, LD_LIBRARY_PATH will also be searched at link (ld) stage after directories specified with -L (also if no -L flag is given).

Why LD_LIBRARY_PATH is bad



回答4:

If I were to guess, I would say that the linker is falling back to using LD_LIBRARY_PATH to resolve libraries that your direct links (e.g., libabc.so, libdef.so, and libghi.so) are dynamically linked against. Looking at the manual page for ld, it looks like linking against an .so that was built using -rpath would affect how the lookup of dynamically bound symbols works.



回答5:

Checking the man for g++, I found out that -lxxxxx option is looking for libxxxxx.a in the provided path -L so at linking time , only .a file will be loaded. At run time, if a library is missing then only library as shared object so .so will be loaded and then it will look in LD_LIBRARY_PATH. On the executable I am working on , I see that in some library directory, there is the version libxxxx.a and libxxxx.so so I think it means that the library can be linked at the linking time or linked at the run time as a shared object.

If a library exists only as shared object , then it means that the library directory path needs to be LD_LIBRARY_PATH to be found at the run time. If a library exists only as an archived so .a , then it means that it needs to be linked at the build of the executable and then -L directorypath and -lxxxxx need to be provided at g++ at compilation time .

This is my understanding .... and at least it is in line with your observations