Julien
Julien

Reputation: 2248

How to keep a free function from a static library in a shared library

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

Answers (1)

Mike Kinghan
Mike Kinghan

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

Related Questions