hfhc2
hfhc2

Reputation: 4391

Library handling of linux / gcc

I am currently working on a bigger project with a lot of libraries included and I have some questions about why gcc under linux behaves the way it does.

First, as I think you might be aware, you can use the "-lxyz" linker flag to gcc/g++ to search for libxyz.so in some system paths and link to it. However, this does not work in the case of static libraries, i.e. if I want to link against libxyz.a I have to add /usr/lib/libxyz.a as an object file explicitely.

My problem is the following: If I want to include a pkg-config style .pc file in my project, what should I put in it if the user chooses to build a static library?

Also, I found it rather annoying that gcc/g++ does not handle library dependencies the way I would expect:

If I link my program against a libabc.so and if ldd tells me that libabc.so depends on libxyz.so then I think that gcc/g++ should be smart enough to also link against libxyz.so. Sadly, this seems not to be the case. Is there any good reason why this does not work or is there a possibility to force gcc/g++ to consider these dependencies?

Upvotes: 0

Views: 219

Answers (1)

Mat
Mat

Reputation: 206659

You don't need to specify full paths for static libraries if you don't want to, but you need to inform the linker that you want to link against static libraries rather than dynamic ones.

This can be done with the -Bstatic argument to ld, which you can pass via gcc or g++ with -Wl,-Bstatic (there are variants, see man ld).

For example:

gcc -o main main.c -Wl,-Bstatic -lfoo -Wl,-Bdynamic -lbar

will link main with a libfoo.a but a libbar.so. Dynamic is the default on platforms that support if (for GNU ld). If you put something like that in a pkg-config setting or similar, it is polite to reset to the default after your static libraries.

As for the second part of your question, it's a bit puzzling because that's not necessary (or good practice in fact) on Linux at least. Your executable should only have NEEDED entries for the libraries it directly depends on. The runtime linker will take care of loading the dependencies of those when necessary. (Why is this good practice? Because you don't want to import indirect dependencies - if a library you depend on changes its own dependencies (after an update for instance), your executable would still load the old dependencies which is problematic and can potentially introduce bugs.)

For example, lets imagine I have main that calls a function in libfoo.so, and that function happens to call a function in libbar.so. The "correct" dependencies to be registered in the executables:

$ readelf -d libbar.so | grep Shared
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
$ readelf -d libfoo.so | grep Shared
 0x0000000000000001 (NEEDED)             Shared library: [libbar.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
$ readelf -d a.out | grep Shared
 0x0000000000000001 (NEEDED)             Shared library: [libfoo.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]

ldd (which calls the runtime linker to do its job) can figure everything out:

$ ldd a.out 
linux-vdso.so.1 (0x00007fff813ff000)
libfoo.so => ./libfoo.so (0x00007f48ee99d000)
libc.so.6 => /lib64/libc.so.6 (0x00007f48ee5c8000)
libbar.so => ./libbar.so (0x00007f48ee3c6000)
/lib64/ld-linux-x86-64.so.2 (0x00007f48eeb9f000)

Upvotes: 1

Related Questions