How to fix “DSO missing from command line”

Back when I was coding in C, I found a very strange problem: the ld library has been linked in the plug-in loader, but when the application is linked to the plug-in loader, it still needs to link ld explicitly. Otherwise, it will report: DSO missing from command line. It means the dynamic library is not specified on the command line.

/usr/bin/ld: /tmp/ccDQXTKy.o: undefined reference to symbol '_Z5funB2v' .//libB.so: error adding symbols: DSO missing from command line collect2: error: ld returned 1 exit status
Code language: JavaScript (javascript)

The DSO missing from command line message will be shown when the linker can’t find the required symbol with its normal search, but the symbol is available in one of the dependencies of a directly specified dynamic library.

In the past, the linker thought that symbols in languages that depended on other languages were available. But in a later version, that changed, and now the linker has a stricter view of what is available. So, the message is meant to help with this change.

Reproduce the error

Let’s take a look at an example: When linking an executable file, it depends on libA.so, and libA.so depends on libB.so, and the function in libB.so is directly called in the executable file, then the link An error will occur.

libA.so is explicitly linked to libB.so during the compilation process. The executable file uses the function of libB.so, binuntils version ≥ 2.22.

Not much to say , let’s take a look at the code that can reproduce the problem

Below is the source code of libB.so:

#include <stdio.h> int funB1(){ printf("in funB1"); return 0; } libB.so int funB2(){ printf("in funB2"); return 0; }
Code language: PHP (php)

There are two functions: funB1 and funB2.
The funB1 function will be called by libA, and the funB2 will be called by the executable file.

Now we compile libB.so:

gcc libB.cpp -fPIC -shared -o libB.so
Code language: CSS (css)

Below is the source code of libA.so:

#include <stdio.h> int funB1(); int funA1(){ printf("in funA1 \n"); funB1(); return 0; }
Code language: PHP (php)

There is only one function funA1 in this library, which calls funB1 function in libB. And this function will then be called by the executable file.

Compile libA.so:

$ gcc libA.cpp -fPIC -shared -o libA.so -Wl,-rpath=./ -L./ -lB

Below is the source code of main.cpp:

int funA1(); int funB2(); int main(){ funA1(); funB2(); return 0; }
Code language: JavaScript (javascript)

Compile main.cpp: (compilation method to reproduce the error)

gcc main.cpp -L./ -lA

When we compiled main.cpp using gcc main.cpp -L./ -lA, the DSO missing from command line error will be printed out.

/usr/bin/ld: /tmp/ccDQXTKy.o: undefined reference to symbol '_Z5funB2v' .//libB.so: error adding symbols: DSO missing from command line collect2: error: ld returned 1 exit status
Code language: JavaScript (javascript)

Let’s use the following command to see if libA.so specify to use libB.so.

$ ldd libA.so

The output contains some useful information:

linux-vdso.so.1 => (0x00007ffd09def000) libB.so => ./libB.so (0x00007fc513d7d000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc5139b3000) /lib64/ld-linux-x86-64.so.2 (0x00007fc514181000)
Code language: PHP (php)

Obviously libA.so has explicitly indicated that I want to rely on libB.so, so why did libA.so be linked when compiling main.cpp, but GCC also asked us to explicitly link libB.so?

How to fix DSO missing from command line

The answer is simple, that is, GCC just wants you to link it explicitly.

Since binutils version 2.22, if you use functions in the dynamic library that you depend on, you must also explicitly specify the dynamic library on which the dynamic library you depend depends on.

In fact, this is binutils after version 2.22, with the --no-copy-dt-needed-entries option turned on by default. When this option is enabled, the compiler will not recursively fetch dependencies that depend on dynamic libraries when linking, so the above problem occurs. Below is the help message on --no-copy-dt-needed-entries:

--copy-dt-needed-entries --no-copy-dt-needed-entries This option affects the treatment of dynamic libraries referred to by DT_NEEDED tags inside ELF dynamic libraries mentioned on the command line. Normally the linker won't add a DT_NEEDED tag to the output binary for each library mentioned in a DT_NEEDED tag in an input dynamic library. With --copy-dt-needed-entries specified on the command line however any dynamic libraries that follow it will have their DT_NEEDED entries added. The default behaviour can be restored with --no-copy-dt-needed-entries. This option also has an effect on the resolution of symbols in dynamic libraries. With --copy-dt-needed-entries dynamic libraries mentioned on the command line will be recursively searched, following their DT_NEEDED tags to other libraries, in order to resolve symbols required by the output binary. With the default setting however the searching of dynamic libraries that follow it will stop with the dynamic library itself. No DT_NEEDED links will be traversed to resolve symbols.

This roughly means that libraries that follow --no-copy-dt-needed-entries do not traverse their dependencies, and the opposite is true for --no-copy-dt-needed-entries. That is, using the following command to compile the main.cpp can avoid this problem.

$ gcc main.cpp -L./ -Wl,--copy-dt-needed-entries -lA

Alternatively, you can use the option -Wl,--copy-dt-needed-entries to allow a more permissive view of symbols.

Common ways to inject this into a build are to export LDFLAGS before running `configure:

export LDFLAGS="-Wl,--copy-dt-needed-entries"
Code language: JavaScript (javascript)

We hope that the information above is useful and helped you successfully fix the DSO missing from command line error message.

We’ve also written a few other guides on C programming, such as unistd.h on Windows and How to automatically indent your code in Visual Studio Code.

If you have any questions, then please feel free to ask in the comments below.

Leave a Comment