Compiling with -Static-Libgcc -Static-Libstdc++ Still Results in Dynamic Dependency on Libc.So

Linking with dynamic library with dependencies

It looks like you are most of the way there already. Well done with your investigation. Let's see if I can help clear up the 'why' behind it.

Here's what the linker is doing. When you link your executable ('main' above) it has some symbols (functions and other things) that are unresolved. It will look down the list of libraries that follow, trying to resolve unresolved symbols. Along the way, it finds that some of the symbols are provided by, so it notes that they are now resolved by this library.

However, it also discovers that some of those symbols use other symbols that are not yet resolved in your executable, so it now needs to resolve those as well. Without linking against, your application would be incomplete. Once it links against, all symbols are resolved and linking is complete.

As you saw, the use of -unresolved-symbols-in-shared-libs, doesn't fix the problem. It just defers it so that those symbols are resolved at run time. That's what -rpath is for: to specify the libraries to be searched at run time. If those symbols can't be resolved then, your app will fail to start.

It's not an easy thing to figure out library dependencies because a symbol could be provided by more than one library and be satisfied by linking against any one of them.

There is another description of this process here: Why does the order in which libraries are linked sometimes cause errors in GCC?

G++ Dynamic Library Linking Issues

(You haven't shown the actual linker error, or provided nearly enough information about the problem, so what follows is partly guesswork...)

If I try to link application D just to, I get unresolved symbols for the symbols in A and B.

When linking an executable the GNU linker checks that all symbols are available. You can turn that off with --allow-shlib-undefined (to tell GCC to pass that to the linker use -Wl,--allow-shlib-undefined)

It is better not to use that option, but in that case the linker needs to know where to find and so it can check that the symbols needed by will be found. You can do that with the -rpath-link linker option

When using ELF or SunOS, one shared library may require another. This happens when an "ld -shared" link includes a shared library as one of the input files.

When the linker encounters such a dependency when doing a non-shared, non-relocatable link, it will automatically try to locate the required shared library and include it in the link, if it is not included explicitly.

So you should be able to fix the problem by using -Wl,-rpath-link,. to tell the linker to look in the current directory (.) for the libraries depends on.

I get the impression that link order matters. How so, and how do I know what order to link in?

Yes, link order matters. You should link in the obvious order ;-) If a file depends on a library then put the library later in the linker line, so it will be found after processing, and if that library depends on another library put that even later, so it will be processed after the earlier library that needs it. If you put a library at the start of the link line then the linker doesn't have any unresolved symbols to look up, so doesn't need to link to that library.

Add dynamic dependency to shared object in C++

Probably the dependency is not listed in the ldd's output because no symbols which are used in B.cpp are found in This may happen because of C++ symbol names mangling: if has been compiled by the C compiler, it may store the symbol for function void foo() under pretty name foo, whereas C++ compiler will mangle it into something like _Z3foov. You can check it with the following commands:

$ # Replace "SomeSharedObject" with the actual name of symbol exported by
$ strings | grep SomeSharedObject
$ strings | grep SomeSharedObject

To avoid this, one could put the declaration of the symbol foo into an extern "C" {} clause. Then compiler will not mangle this name, and linker will probably find this name in

The -l option works as you expect in a laboratory environment:

$ cat bar.cpp 
extern void foo();

void bar()
$ cat baz.cpp
extern void bar();

void baz()
$ # Link against (OpenSSL).
$ # Obviously is unnecessary in
$ g++ -fPIC -shared bar.cpp -o -lssl
$ ldd
statically linked
$ # Link against in the current directory
$ g++ -fPIC -shared baz.cpp -o -L`pwd` -lbar
$ ldd => (0x00007fff7cfe2000) => not found

Here depends on the function foo. But it hasn't been found in any library, including So ldd reports the shared object as "statically linked". All symbols which were not found when was produced, will be searched for when creating the final executable which depends on

In turn, depends on, because the function void bar() was found in the above shared object which we have specified via -l option. If we omit the -L option, linker would report error like -lbar: not found. If we omit both -L and -l, would not depend on any shared object just as

Dynamic Linking of Shared Libraries with Dependencies

I experienced a similar situation, this is what worked for me (using a gcc toolchain):

When you create the shared object, you unconditionally link the library, the command should look like this:

gcc -shared -Wl,--no-as-needed -lA -o b.o

You can then check that indeed became a dependency for the dynamic linker:

$ ldd => (0xb77ba000) => not found => /lib/i386-linux-gnu/ (0xb75f7000)
/lib/ (0xb77bb000)

In your main program it should be sufficient to only dlopen() the library, and the other library should get linked automatically by the dynamic linker.

Ineffective to use patchelf to add a declared dependency on a dynamic library

This errror:

ld: xxx/intel/oneapi/compiler/2021.2.0/linux/bin/intel64/.../ error loading plugin: /lib64/ version `GLIBC_2.14' not found. 

appears to be coming from ld.

same errors when using ifort and icc

It looks like both ifort and icc are using linker plugin to perform LTO (link-time optimization).

You need to patchelf the binary which actually fails (ld in this case), not the binary which merely invokes ld (i.e. leave ifort and icc alone).

Usually you can tell the compiler to print more info about the binaries it invokes with e.g. icc -v <rest of command>.

I expect that there is ld (or possibly ld.lld) under .../intel/oneapi/compiler/2021.2.0/linux/..., and you need to patchelf that binary.

Dynamic library forwarding

No, it is not possible to "forward" dynamically linked libraries.

When you link against any library, statically or dynamically, you actually enable your main executable to call on the functions/symbols defined in the linked library.

In your case, the library bar, does not have the function foo() defined in it. So when is created, the symbols generated are registered in the symbol table of your main executable - program. As, the symbols in the bar lib do not contain any function called foo(), it doesn't get registered in the symbol table of program. So when foo() gets called during time, the loader tries to find the .so in which foo() would be defined among all the libraries you linked during compiling program. Hence the run time error. It doesn't show a compile time error because you had included the foo.h header file to it.

You need to explicitly link all the libraries of which symbols(functions, variables, constants, etc.) you want to reference in the code being compiled.

How does a compiler find out which dynamic link library will be used in my code, if I only include headers-files, where is not describe it?

When you compile a runnable executable, you don't just specify the source code, but also a list of libraries from which undefined references are looked up. With the C standard library, this happens implicitly (unless you tell GCC -nostdinc), so you may not have been consciously aware of this.

The libraries are only consumed by the linker, not the compiler. The linker locates all the undefined references in the libraries. If the library is a static one, the linker just adds the actual machine code to your final executable. On the other hand, if the library is a shared one, the linker only records the name (and version?) of the library in the executable's header. It is then the job of the loader to find appropriate libraries at load time and resolve the missing dependencies on the fly.

On Linux, you can use ldd to list the load-time dependencies of a dynamically linked executable, e.g. try ldd /bin/ls. (On MacOS, you can use otool -L for the same purpose.)

Linking against an old version of libc to provide greater application coverage

Work out which symbols in your executable are creating the dependency on the undesired version of glibc.

$ objdump -p myprog
Version References:
required from
0x09691972 0x00 05 GLIBC_2.3
0x09691a75 0x00 03 GLIBC_2.2.5

$ objdump -T myprog | fgrep GLIBC_2.3
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.3 realpath

Look within the depended-upon library to see if there are any symbols in older versions that you can link against:

$ objdump -T /lib/ | grep -w realpath
0000000000105d90 g DF .text 0000000000000021 (GLIBC_2.2.5) realpath
000000000003e7b0 g DF .text 00000000000004bf GLIBC_2.3 realpath

We're in luck!

Request the version from GLIBC_2.2.5 in your code:

#include <limits.h>
#include <stdlib.h>

__asm__(".symver realpath,realpath@GLIBC_2.2.5");

int main () {
realpath ("foo", "bar");

Observe that GLIBC_2.3 is no longer needed:

$ objdump -p myprog
Version References:
required from
0x09691a75 0x00 02 GLIBC_2.2.5

$ objdump -T myprog | grep realpath
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 realpath

For further information, see

Related Topics

Leave a reply