Reputation: 2248
When I build a shared library from a static library, its free functions disappear. I know a workaround to keep the symbol in the final library but I would like to understand why I need this workaround in the first place.
Let's consider this source file:
extern "C" void HERE_I_AM() {}
If I execute the following commands
g++ test.cpp -shared -o libtest-without-static.so
nm libtest-without-static.so
I can see that the function is available in the shared library:
…
0000000000201000 d _GLOBAL_OFFSET_TABLE_
w __gmon_start__
0000000000000590 r __GNU_EH_FRAME_HDR
0000000000000580 T HERE_I_AM <-- HERE
0000000000000468 T _init
w _ITM_deregist
…
But if I compile the file in a static library first
g++ -c test.cpp
ar crf libtest.a test.o
g++ -shared libtest.a -o libtest-with-static.so
nm libtest-with-static.so
Then the function is not in the shared library:
0000000000201020 B __bss_start
0000000000201020 b completed.7641
w __cxa_finalize
0000000000000440 t deregister_tm_clones
00000000000004d0 t __do_global_dtors_aux
0000000000200e88 t __do_global_dtors_aux_fini_array_entry
0000000000201018 d __dso_handle
0000000000200e90 d _DYNAMIC
0000000000201020 D _edata
0000000000201028 B _end
000000000000051c T _fini
0000000000000510 t frame_dummy
0000000000200e80 t __frame_dummy_init_array_entry
0000000000000528 r __FRAME_END__
0000000000201000 d _GLOBAL_OFFSET_TABLE_
w __gmon_start__
0000000000000408 T _init
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
0000000000000480 t register_tm_clones
0000000000201020 d __TMC_END__
I know that I can get the function in the shared library either by using -Wl,--whole-archive
or by having a class member function using a symbol of the static library, but I don't get why the above commands do not produce the same shared library.
Upvotes: 1
Views: 623
Reputation: 61317
When the linker encounters an object file, foo.o
in the input sequence it
links it unconditionally into the output file (program or shared library).
When it encounters a static library, libbar.a
, it will (by default) examine the archive
to find any object files, e.g. libbar.a(foo.o)
that provide definitions for unresolved
symbols that have been referenced by object files (or shared libraries) already
linked.
If it finds any such object files it extracts them from the archive and links them into the output file, exactly as if they were individually listed in the commandline and the static library not mentioned at all. If it doesn't find any, the archive contributes nothing to the linkage.
In your first compilation-and-linkage:
$ g++ test.cpp -shared -o libtest-without-static.so
g++
breaks it down (as it must) into a compile step and a link step, effectively:
$ g++ -c -o temporary.o test.cpp
$ g++ temporary.o -shared -o libtest-without-static.so
in which temporary.o
is linked unconditionally.
In your second linkage:
$ g++ -shared libtest.a -o libtest-with-static.so
the solitary archive member libtest.a(test.o)
fails to define any unresolved
references that have already been linked, because there aren't any. libtest.a
contributes nothing to the linkage of the shared library and the output shared library
contains no symbols but the boilerplate provided by the default libraries of a g++ -shared ...
linkage.
The default purpose of static libraries in linkage, as distinct from individually named object files, is
to offer the linker a bag of object files from which to select just those it needs to
satisfy unresolved references already in hand. You don't need to know exactly which ones they will be. You just
need to know they're in that bag. You have to link at least one object file before
any static library if there are going to be any unresolved references that static library
members might satisfy. Or specify --whole-archive
.
Upvotes: 1