I've a program that I must build. The program depends on libA, and libA depends on libB. Both libs are in the same folder but ldd libA.so does not include libB.so so I must add it while linking it.
This is my gcc command:
gcc -L/path/to/libraries/lib -lA -lB -I/path/to/libraries/include main.cpp
The program builds and links, but it does not start. It gives me following error:
./a.out: symbol lookup error: /path/to/libraries/lib/libA.so: undefined symbol: symbol_used_in_libA_but_defined_in_libB
With ldd I can see that libB.so is not included in my binary:
linux-vdso.so.1 => (0x00007fffaecd9000)
libA.so => /path/to/libraries/lib/libA.so (0x00007effc02a4000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007effbfebb000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007effbfca5000)
/lib64/ld-linux-x86-64.so.2 (0x00007effc05cb000)
I have these conditions:
/path/to/libraries is inside LD_LIBRARY_PATH
running ldconfig is ok and ldconfig -p find both libA.so and libB.so
If in gcc command I change -lB with -lBB it gives me a linker error, so I think that gcc find correctly libB.so even if it does not link it inside the executable.
What I'm doing wrong? What I can do in order to link the executable to both libraries?
Most Linux distributions (I assume you are using Linux based on the output of ldd) seem to configure gcc as to pass --as-needed to ld by default (e.g., see here for Debian). This means the final library/executable will only depend on a library (i.e., have a DT_NEEDED tag for that library) if some symbol of that library is actually used by the library/executable.
In your case, main.cpp does not use any functions of libB so the linker does not add libB as a dependency of the final executable. You can work around it by passing the --no-as-needed flag to the linker. E.g.,
gcc -Wl,--no-as-needed ...
Of course, the proper fix is to relink libA and make sure it lists libB as a dependency.
Related
I am attempting to create a shared library that provides an easier interface for calling FFT and IFFT functions from GSL in C.
My C file.
fft.c
Building the object file.
gcc -c -Wall -Wextra -O2 -fPIC fft.c -o fft.o
Object file builds perfectly.
Then the link command.
gcc -L/usr/local/lib -Wl,-rpath=/usr/local/lib -shared -o libfft.so fft.o -lgsl -lgslcblas
No errors...
However, running the following command
ldd libfft.so
prints the following output.
linux-vdso.so.1 found
libgsl.so => /usr/local/lib/libgsl.so <--- CORRECT
libc.so.6 => found
libm.so.6 => found
/lib64/ld-linux-x86-64.so.2
libgslcblas.so => not found <--- This is confusing me...
For some reason the libgsl.so is found in the correct location on my computer, but the libgslcblas.so is saying not found.
Both libraries are in that directory.
Thank you so much for any answers.
EDIT (09/07/2022)
After looking into the recommendation by
https://stackoverflow.com/users/2581418/vitsoft
the Dynamic section of the shared library was only showing libgsl.so as being (NEEDED). Then I thought maybe the actual libgsl.so I have is dependent upon libgslcblas.so.
Running the ldd command on libgsl.so, shows that it relies on libgslcblas.so, and it is not found. So, I may have built GSL incorrectly from source?..
This was exactly the problem, make sure to follow the directions of GSL when they tell you how to build their source code!
I am trying to build libass into a shared library with static linking under MinGW-w64. When I configure with
./configure --disable-static --enable-shared
it generates the shared library (dynamically-linked) as expected. However, when I attempt to force static linking by setting
LDFLAGS=-static
instead of generating a statically-linked shared library (.dll with no dependency), it generates a static library (.a).
I am almost certain that I have all the dependent static libraries and no error or warning message is shown in the make process.
Can anyone please shed some light on what I'm doing wrong?
libtool says No.
The package's stock autotools ltmain.sh script parses the linkage flags and
if it finds -static it will not build a shared library, just a static
one.
Which is the most it could reasonably do, because you can't statically link a shared
library. A shared library must consist entirely of Position Independent (PIC)
code or the linkage will fail, whereas a static linkage will call for the linkage
of non-PIC object files, contributed by the non-PIC standard and runtime libraries,
if nothing else.
foo.c
#include <stdio.h>
void foo(void)
{
puts("foo");
}
Build a dynamically linked shared library:
$ gcc -c -fPIC foo.c
$ gcc -shared -o libfoo.so foo.o
$ file libfoo.so
libfoo.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), \
dynamically linked, BuildID[sha1]=1adff7204d84d138a80bc4b6f3f38211e4b42812, \
not stripped
Attempt to build a statically linked shared library:
$ gcc -c -fPIC foo.c
$ gcc -shared -static -o libfoo.so foo.o
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/6/crtbeginT.o: \
relocation R_X86_64_32 against hidden symbol `__TMC_END__' cannot be used \
when making a shared object
/usr/bin/ld: final link failed: Nonrepresentable section on output
collect2: error: ld returned 1 exit status
The static lib is just an ar package.
You can use command of ar to make the pack and unpack it.
I'm running into an issue after upgrading gcc from 4.1.1 to 4.7.2. The problem is that the ld --as-needed flag is not pruning libraries that are not required if enough libraries with inter dependencies are listed.
For example, if I build a simple program that doesn't need any special libraries, but includes them on the build line, as such
gcc -m32 test.c -Wl,--as-needed -L/usr/local/lib -lrt -lprojcommon -lproj -lrte -o test
then it builds fine and the --as-needed flag does it's job pruning out all of the listed libs that are not needed.
ldd test
linux-gate.so.1 => (0x00bfc000)
libc.so.6 => /lib/libc.so.6 (0x001ac000)
/lib/ld-linux.so.2 (0x0018a000
However, if I add one more library (in this case crypto), then the build fails with undefined reference errors.
gcc -m32 test.c -Wl,--as-needed -L/usr/local/lib -lcrypto -lrt -lprojcommon -lproj -lrte -o test
/usr/local/lib/librte.so: error: undefined reference to 'tla_decap_data'
/usr/local/lib/librte.so: error: undefined reference to 'do_db'
collect2: error: ld returned 1 exit status
This exact same build worked with 4.1.1, but started failing with 4.7.2.
This is part of a general build infra and libraries included on the build line are generic and expected to be pruned via --as-needed. I could fix this with --allow-shlib-undefined, but I'd prefer to find real unresolved symbols at build time. If I do set --allow-shlib-undefined, then I end up with the same set of required libs as the build that worked.
Any insight would be appreciated.
I have a static libary mylib that depends on the math library.
If I first link mylib with math and then to my executable it works:
add_executable(myapp main.c)
target_link_libraries(mylib m)
target_link_libraries(myapp mylib)
But if I do the linking directly with the executable it fails when using gcc (with clang it works!)
add_executable(myapp main.c)
target_link_libraries(myapp m mylib)
Why does this make any difference?
I thought that it is anyway not possible to link libraries together?
When using cmake's target_link_libraries it does not mean you will link anything. It rather will create a dependency between a target and a library of type/action link.
I guess that the actually build line of the first example will result in something like that:
gcc -o myapp myapp.o -lmylib -lm
and the second one
gcc -o myapp myapp.o -lm -lmylib
. If mylib has references to m the second example (might) not link.
Try to run make VERBOSE=1 and study the command-line of the link-process to really understand what's happening. The linker of clang is maybe intelligent and waits for all calls to be linked before actually dropping a library during the link-process.
When using target_link_libraries it matters in which order you specify linked libraries.
This does not work when using gcc (at least in v4.6.3):
target_link_libraries(myapp m mylib)
while this works:
target_link_libraries(myapp mylib m)
So all libraries mylib depends on have to come after mylib.
If you track down the actual linker invocation with make VERBOSE=1 you will find this for the broken example:
gcc main.c.o -o luatest -rdynamic -lm mylib.a
and this for the working one:
gcc main.c.o -o luatest -rdynamic mylib.a -lm
Invoking clang with the exact same parameters works in both cases!
So #PatrickB seems to be right:
The linker of clang is maybe intelligent and waits for all calls to be
linked before actually dropping a library during the link-process.
Consider the following scenario:
Shared Library libA.so ,with no dependencies.
Shared Library libB.so, with libA.so as its dependency.
I want to compile a binary file that links with the libB.
Should I link the binary with libB only or with libA either?
Is there any way to link only with the direct dependencies, letting the resolution of unresolved symbols from the dependencies for runtime?
I'm worried about the fact that the library libB implementation may change in the future, introducing other dependencies (libC, libD, libE for instance). Am I going to have problems with that?
In other words:
libA files: a.cpp a.h
libB files: b.cpp b.h
main program files: main.cpp
Of course, b.cpp includes a.h and main.cpp includes b.h.
Compilation commands:
g++ -fPIC a.cpp -c
g++ -shared -o libA.so a.o
g++ -fPIC b.cpp -c -I.
g++ -shared -o libB.so b.o -L. -lA
Which of the bellow options should I use?
g++ main.cpp -o main -I. -L. -lB
or
g++ main.cpp -o main -I. -L. -lB -lA
I couldn't use the first option. The linker complains about the unresolved symbols from the library libA. But it sound a little strange to me.
Thanks very much.
-- Updated comments:
When I link the binary, the linker will try to resolve all symbols from the main and the libB. However, libB has undefined symbols from the libA. That's why the linker complains about that.
That's why I need to link with the libA too.
However I found a way to ignore unresolved symbols from shared libraries.
Looks like I should use the following command line to do that:
g++ main.cpp -o main -I. -L. -lB -Wl,-unresolved-symbols=ignore-in-shared-libs
Looks like it is still possible to use the -rpath option.
However I need to understand it a little better.
Does anyone knows any possible pitfalls when using the -Wl,-unresolved-symbols=ignore-in-shared-libs option?
-- Updated comments 2:
-rpath should not be used for this purpose. It is useful to force a library to be found in a given directory. The -unresolved-symbol approach looks much better.
Thanks again.
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 libB.so, 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 libA.so, your application would be incomplete. Once it links against libA.so, 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?
For dynamic linking only with direct dependencies you can use -Wl,--as-needed with adding the libs after -Wl,--as-needed:
gcc main.c -o main -I. -L. -Wl,--as-needed -lB -lA
For checking the direct dependencies you should use readelf instead of ldd because ldd also shows the indirect dependencies.
$ readelf -d main | grep library
0x0000000000000001 (NEEDED) Shared library: [libB.so]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
ldd also shows the indirect dependencies:
$ LD_LIBRARY_PATH=. ldd ./main
linux-vdso.so.1 (0x00007fff13717000)
libB.so => ./libB.so (0x00007fb6738ed000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb6734ea000)
libA.so => ./libA.so (0x00007fb6732e8000)
/lib64/ld-linux-x86-64.so.2 (0x00007fb673af0000)
If you use cmake, you can add the following lines to include only direct dependencies:
set(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed ${CMAKE_EXE_LINKER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--as-needed ${CMAKE_SHARED_LINKER_FLAGS}")
Another option is to use libtool
If you change the g++ call to libtool --mode=compile g++ to compile the source code and then libtool --mode=link g++ to create the application off of libB, then libA will be linked automatically.
This is an interesting post - I was banging my head with this as well, but I think you miss a point here..
The idea is as follows, right ?
main.cpp =(depends)=> libB.so =(depends)=> libA.so
Let's further consider that ..
In a.cpp (and only there) you define a class / variable, let's call it "symA"
In b.cpp (and only there) you define a class / variable, let's call it "symB".
symB uses symA
main.cpp uses symB
Now, libB.so and libA.so have been compiled as you described above. After that, your first option should work, i.e.:
g++ main.cpp -o main -I. -L. -lB
I guess that your problem originates from the fact that
in main.cpp you also refer to symA
Am I correct?
If you use a symbol in your code, then that symbol must be found in an .so file
The whole idea of inter-referencing shared libraries (i.e. creating APIs), is that the symbols in the deeper layers are hidden (think of peeling onions) and not used.
.. i.e. don't refer to symA in your main.cpp, but only to symB instead (and let symB to refer symA only).