Reputation: 800
Let's suppose we have a library libutils.so:
ldd libutils.so
...
libdependency.so
...
Let's further suppose that we need to build an application:
g++ appliation.cpp -lutils -o application
May we omit -ldependency in the above command or must we write:
g++ appliation.cpp -lutils -ldependency -o application
Upvotes: 1
Views: 416
Reputation: 61192
May we omit -ldependency in the above command
If you control the linkage of libutils.so
itself, yes you can. An illustration:
main.c
extern void foo(void);
int main(void)
{
foo();
return 0;
}
foo.c
extern void bar(void);
void foo(void)
{
bar();
}
bar.c
#include <stdio.h>
void bar(void)
{
puts(__func__);
}
We'll make a program that depends on libfoo.so
, which depends on libbar.so
.
Make the object files:
$ gcc -Wall -c -fPIC foo.c bar.c
gcc -Wall -c main.c
Now link libbar.so
the No Frills way:
$ gcc -shared -o libbar.so bar.o
Next link libfoo.so
like this:
$ gcc -shared -o libfoo.so foo.o -L. -lbar -Wl,-rpath=$(pwd)
The effect of the -rpath linker option
is:
-rpath=dir
Add a directory to the runtime library search path. This is used when linking an ELF executable with shared objects. All -rpath arguments are concatenated and passed to the runtime linker, which uses them to locate shared objects at runtime. The -rpath option is also used when locating shared objects which are needed by shared objects explicitly included in the link; see the description of the -rpath-link option. If -rpath is not used when linking an ELF executable, the contents of the environment variable LD_RUN_PATH will be used if it is defined.
The result is that:
$ objdump -x -j .dynamic libfoo.so | egrep '(RUNPATH|NEEDED)'
NEEDED libbar.so
RUNPATH /home/imk/develop/so/scrap
libfoo.so
has a NEEDED
entry inscribed in its .dynamic
section saying that
the library has a runtime dependency on libbar.so
. Likewise it has
a RUNPATH
entry there saying that runtime dependencies may be searched for in /home/imk/develop/so/scrap
That's just the pwd
where I did the linkage: it doesn't have to be that, as long as is indeed
a directory where libbar.so
can be found when the linker or loader comes looking for it.
This information can be read by the linker, when libbar.so
is linked with something else,
and by the loader at runtime. So finally I can link prog
like this:
$ gcc -o prog main.o -L. -lfoo -Wl,-rpath=$(pwd)
I don't need to mention -lbar
, because libfoo.so
itself provides the linker with
the information that libfoo.so
depends on libbar.so
, and where to look for it.
Since I also passed -rpath=$(pwd)
in the linkage of prog
, we see that prog
will provide this information
$ objdump -x -j .dynamic prog | egrep '(RUNPATH|NEEDED)'
NEEDED libfoo.so
NEEDED libc.so.6
RUNPATH /home/imk/develop/so/scrap
to the runtime loader: prog
needs libfoo.so
, and it can be looked for
in /home/imk/develop/so/scrap
. When the loader finds libfoo.so
and loads it, it will
discover from it that:
NEEDED libbar.so
RUNPATH /home/imk/develop/so/scrap
and will in turn find and load libbar.so
, which will enable it to resolve all
symbols referred to in the process under construction. Consequently, prog
can be run immediately:
$ ./prog
bar
I didn't have to pass -rpath=$(pwd)
in the linkage of prog
. But if I hadn't:
$ gcc -o prog main.o -L. -lfoo
$ ./prog
./prog: error while loading shared libraries: libfoo.so: cannot open shared object file: No such file or directory
the loader wouldn't know where to find libfoo.so
. See:
$ ldd prog
linux-vdso.so.1 (0x00007ffffcc35000)
libfoo.so => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f4d1aff9000)
/lib64/ld-linux-x86-64.so.2 (0x00007f4d1b5ec000)
And then I'd have to resort to:
$ export LD_LIBRARY_PATH=.
$ ldd prog
linux-vdso.so.1 (0x00007fff964dc000)
libfoo.so => ./libfoo.so (0x00007fc2a7f35000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc2a7b44000)
libbar.so => ./libbar.so (0x00007fc2a7942000)
/lib64/ld-linux-x86-64.so.2 (0x00007fc2a8339000)
$ ./prog
bar
Later
it is still a little bit unclear whether the presence of libdependency.so among the output of ldd libutils.so is enough to omit -ldependencny during linkage
You would need to ask at least one and at most two questions about the output of ldd utils.so
:-
ldd libutils.so
output report the so-name libdependency.so
at all?If No to 1 then libdutils.so
contains no informatation about its dependency of libdependency.so
and you must specify -lutils -ldependency
in any further linkage.
If Yes to 1 but No to 2 (i.e.ldd libutils.so
reports libdependency.so => not found
) then libutils.so
has
a NEEDED
entry for the so-name libdependency.so
but not a RUNPATH
entry by which the linker or
loader can resolve that so-name to any actual file. In that case again, you must link -lutils -ldependency
if you link -lutils
, so that the linker will then search for a file that resolves -ldependency
. At least, you must do so as long as ldd libutils.so
still reports libdependency.so => not found
when you do the linkage. Read on...
If Yes to 1 and Yes to 2 then you can drop -ldependency
in a further linkage provided it is
run in the same environment in which you ran ldd libutils.so
That caveat is needed because if ldd libutils.so
resolves libdependency.so
, all you know
is that ldd
was able to resolve libdependency.so
using the loader's search algorithm:-
LD_LIBRARY_PATH
environment variable (in the active shell), lists a directory
in which libdependency.so
is found, orlibutils.so
provides a RUNPATH
in which libdependency.so
is found, orlibdependency.so
is found in one of the directories listed in /etc/ld.so.conf
(or the recursive include
-expansion thereof), orlibdependency.so
is found in one of the loader's trusted search directories, /lib
and /usr/lib
If ldd
can resolve libdependency.so
in one of those four ways, then the linker will be able
to do it the same way, as long as that way still succeeds when you do the linkage.
So going back to my example, and my linkage:
$ gcc -shared -o libfoo.so foo.o -L. -lbar -Wl,-rpath=$(pwd)
After that, thanks to -rpath=$(pwd)
. I can link prog
like:
$ gcc -o prog main.o -L. -lfoo
without mentioning -lbar
, and it succeeds. Now I link libfoo.so
instead without
an -rpath
:
$ gcc -shared -o libfoo.so foo.o -L. -lbar
after which:
$ objdump -x -j .dynamic libfoo.so | egrep '(RUNPATH|NEEDED)'
NEEDED libbar.so
there's no RUNPATH
anymore, and consequently:
$ ldd libfoo.so
linux-vdso.so.1 (0x00007ffda05e6000)
libbar.so => not found
because the loader can't resolve libbar.so
in any other way either.
Now I can no longer link prog
without -lbar
:
$ gcc -o prog main.o -L. -lfoo
/usr/bin/ld: warning: libbar.so, needed by ./libfoo.so, not found (try using -rpath or -rpath-link)
./libfoo.so: undefined reference to `bar'
But if I do:
$ export LD_LIBRARY_PATH=$(pwd)
then:
$ ldd libfoo.so
linux-vdso.so.1 (0x00007ffe56d1e000)
libbar.so => /home/imk/develop/so/scrap/libbar.so (0x00007fd2456e8000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd2452f7000)
/lib64/ld-linux-x86-64.so.2 (0x00007fd245aec000)
libfoo.so
's dependency libbar.so
is resolved by the loader, using the LD_LIBRARY_PATH
, and in the
same way by the linker:
$ gcc -o prog main.o -L. -lfoo; echo Done
Done
And if I clear LD_LIBRARY_PATH
again:
$ unset LD_LIBRARY_PATH
$ gcc -o prog main.o -L. -lfoo; echo Done
/usr/bin/ld: warning: libbar.so, needed by ./libfoo.so, not found (try using -rpath or -rpath-link)
./libfoo.so: undefined reference to `bar'
collect2: error: ld returned 1 exit status
Done
back to failure.
Upvotes: 2