Some libraries are not found without LD_LIBRARY_PATH mangling

Thiago Macieira thiago at kde.org
Tue Oct 30 15:17:40 CET 2007


Em Tuesday 30 October 2007 14:44:51 Alexander Neundorf escreveu:
> > We're talking about running uninstalled applications that link to
> > uninstalled libraries. Linking to installed libraries has never been a
> > problem -- the RPATH to the install tree is present anyways.
>
> But not necessarily to RPATH to libraries that library links to, see below.

It doesn't have to. See below.

> > > then A will link just to that and not know about other libraries
> > > libsoprano.so links to (and their directories, which are required for
> > > the RPATH). If libsoprano.so doesn't find its libraries without RPATH
> > > (or RUNPATH), there are two options:
> >
> > Again, stop. libsoprano.so's dependencies are loaded by libsoprano.so
> > itself, not by the application. So it's the dependent library's job to
> > find the libraries the right way (environment variable, ld.so.conf
> > modification, RPATH, whatever).
>
> Yes, we agree here.
> What I still don't know is for which steps is the RPATH valid ?

DT_RPATH is only valid for the libraries loaded by that module's DT_NEEDED 
tags. It doesn't work indirectly.

> Say APP links to libA, and libA links to libB, and APP has an RPATH, is
> this RPATH also valid for finding libB from libA ?

No. libA has to know how to find libB on its own.

Test case:
$ ls -lR
.:
total 12
-rw-r--r-- 1 tmacieir tmacieir   45 2007-10-30 14:57 main.c
drwxr-xr-x 2 tmacieir tmacieir  100 2007-10-30 14:57 ONE/
drwxr-xr-x 2 tmacieir tmacieir  100 2007-10-30 14:58 TWO/

./ONE:
total 12
lrwxrwxrwx 1 tmacieir tmacieir   11 2007-10-30 14:57 libONE.so -> libONE.so.1*
-rwxr-xr-x 1 tmacieir tmacieir 5236 2007-10-30 14:54 libONE.so.1*
-rw-r--r-- 1 tmacieir tmacieir   21 2007-10-30 14:54 main.c

./TWO:
total 12
lrwxrwxrwx 1 tmacieir tmacieir   11 2007-10-30 14:58 libTWO.so -> libTWO.so.1*
-rwxr-xr-x 1 tmacieir tmacieir 5375 2007-10-30 14:57 libTWO.so.1*
-rw-r--r-- 1 tmacieir tmacieir   53 2007-10-30 14:55 main.c

$ cat ONE/main.c
int symbol_ONE() { }
$ ldd ONE/libONE.so
        linux-gate.so.1 =>  (0xb7fe7000)
        libc.so.6 => /lib/i686/libc.so.6 (0xb7e85000)
        /lib/ld-linux.so.2 (0x80000000)

$ cat TWO/main.c
int symbol_ONE(); int symbol_TWO() { symbol_ONE(); }
$ ldd TWO/libTWO.so
        linux-gate.so.1 =>  (0xb7fcd000)
        libONE.so.1 => not found
        libc.so.6 => /lib/i686/libc.so.6 (0xb7e6b000)
        /lib/ld-linux.so.2 (0x80000000)

So, at this point above, you can see that libTWO was compiled linking to 
libONE, but *without* any RPATH setting whatsoever.

If we try to link our test program:
$ cat main.c
int symbol_TWO(); int main() { symbol_TWO; }
$ gcc -o main -LTWO -lTWO main.c
/usr/bin/ld: warning: libONE.so.1, needed by TWO/libTWO.so, not found (try 
using -rpath or -rpath-link)
TWO/libTWO.so: undefined reference to `symbol_ONE'
collect2: ld returned 1 exit status

Oh, well, let's add the -rpath:
$ gcc -o main -LTWO -lTWO main.c -Wl,-rpath,$PWD/ONE:$PWD/TWO
$ ./main
./main: error while loading shared libraries: libONE.so.1: cannot open shared 
object file: No such file or directory

So you see that main's RPATH does *not* apply to libTWO's dependencies.

Now, if we make it a direct dependency:
$ gcc -o main -LTWO -LONE -lTWO -lONE main.c -Wl,-rpath,$PWD/ONE:$PWD/TWO
$ ./main

Works just fine.

Also works if -rpath is set in the dependent library:
$ ldd TWO/libTWO.so
        linux-gate.so.1 =>  (0xb7f50000)
        libONE.so.1 => /tmp/testdir/TWO/../ONE/libONE.so.1 (0xb7f4b000)
        libc.so.6 => /lib/i686/libc.so.6 (0xb7dec000)
        /lib/ld-linux.so.2 (0x80000000)
[rpath was added, so it finds its dependency]
$ gcc -o main -LTWO -lTWO main.c -Wl,-rpath,$PWD/TWO
$ ./main


Conclusions:
1) when linking to uninstalled libraries, we should link to them *all* (so as 
to make all uninstalled dependencies direct ones)
2) each one should clean up after itself: each library should be loadable on 
its own after installed. Having a "not found" in ldd's output means you 
messed up.

> Yes, but for anything except kdelibs any library from kdelibs is an
> "already installed library". Currently they don't get an RPATH at all
> (except with FULL_RPATH option), but when linking to them the full list of
> libs is used (which should produce the correct RPATH for the executable).
> Once the libraries get an RPATH, they already have it in the build tree or
> they will be relinked.

I didn't understand.

> > > > - on ELF platforms without DT_RUNPATH (IRIX, HP-UX):
> > > >   RUN_UNINSTALLED executables are relinked at install time
> > >
> > > This could make some things easier, I think we could even completely
> > > get rid of the RUN_UNINSTALLED argument. Everything, apps and libs
> > > would get the full RPATH (RUNPATH) for the install tree, the shell
> > > scripts which set LD_LIBRARY_PATH are created anyway.
> >
> > That's what I proposed for the platforms using DT_RUNPATH. But mind you:
>
> So we agree, right ?

Yes.

> > the real target (the ELF executable) should have a different name -- the
> > shell script should have the target's name inside the build tree.
>
> I don't feel like changing this now and I don't see a real reason for it.
> The shell script is currently <target>.shell, if you use tab completion you
> notice that there are two executables.

I see a reason for it: if those programs are run uninstalled, it's because 
there's a rule in CMake somewhere that is running them. Are we absolutely 
sure that all places calling them have the ".shell" if it's inside kdelibs 
but no ending if it's not?

> Yes, FULL_RPATH is ok, my only problem is the time the relinking takes.
> It's even better than RUNPATH+LD_LIBRARY_PATH (because you can run it
> directly and don't have to use a script).

FULL_RPATH+RUNPATH+LD_LIBRARY_PATH is the best solution I see. Distributions, 
however, probably won't use RPATH at all, so LD_LIBRARY_PATH also applies to 
them and works fine. (Then again, distributions don't have the installed 
libraries in their build environments, so even if RPATH is there, it will 
find no library)

As far as I can see, relinking is necessary only on AIX and on ELF without 
RUNPATH.

> I'll put chrpath on my TODO.

I did take a look at it once and my conclusion was that increasing the RPATH 
entry would require rewriting the entire ELF file. That's not an easy task 
and requires the tool to actually understand ELF. Don't forget that there are 
some ELF binaries that are several megabytes in size.

However, since we're talking about *removing* path entries from RPATH 
(removing the build tree path), it should be always possible, since you 
decrease the length of the tag.

-- 
  Thiago Macieira  -  thiago (AT) macieira.info - thiago (AT) kde.org
    PGP/GPG: 0x6EF45358; fingerprint:
    E067 918B B660 DBD1 105C  966C 33F5 F005 6EF4 5358
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: This is a digitally signed message part.
Url : http://mail.kde.org/pipermail/kde-buildsystem/attachments/20071030/a2674712/attachment.pgp 


More information about the Kde-buildsystem mailing list