Turning a statically linked library into a dynamic one

1.2k views Asked by At

I know this question has been asked a few times, but none of the solutions have worked for me. I have a statically linked library that I would like to use with a JNI layer with versions pre Java 8. Based on my reading of "how to link static library into dynamic library in gcc", it seems possible. Here is my command line:

/usr/bin/g++ -shared -std=c++0x -D__extern_always_inline=inline -Wall -pedantic -O3 -fomit-frame-pointer -fno-strict-aliasing -D_FILE_OFFSET_BITS=64 -DNDEBUG -fPIC -Wl,--whole-archive target/vw_jni.a -o target/vw_jni.lib

This is based on writing a JNI layer to the Vowpal Wabbit library.

At this point in the build process I have statically created a file called target/vw_jni.a through static linking

target/vw_jni.a: In function `_fini': (.fini+0x0): multiple definition of `_fini' /usr/lib/gcc/x86_64-linux-gnu/4.9/../../../x86_64-linux-gnu/crti.o:(.fini+0x0): first defined here target/vw_jni.a: In function `data_start': (.data+0x8): multiple definition of `__dso_handle' /usr/lib/gcc/x86_64-linux-gnu/4.9/crtbeginS.o:(.data.rel.local+0x0): first defined here target/vw_jni.a: In function `_init': (.init+0x0): multiple definition of `_init' /usr/lib/gcc/x86_64-linux-gnu/4.9/../../../x86_64-linux-gnu/crti.o:(.init+0x0): first defined here /usr/lib/x86_64-linux-gnu/libc_nonshared.a(elf-init.oS): In function `__libc_csu_init': (.text+0x0): multiple definition of `__libc_csu_init' target/vw_jni.a:(.text+0x1cea20): first defined here /usr/lib/x86_64-linux-gnu/libc_nonshared.a(elf-init.oS): In function `__libc_csu_fini': (.text+0x70): multiple definition of `__libc_csu_fini' target/vw_jni.a:(.text+0x1ceab0): first defined here /usr/lib/gcc/x86_64-linux-gnu/4.9/crtendS.o:(.tm_clone_table+0x0): multiple definition of `__TMC_END__' target/vw_jni.a:(.data+0x2630): first defined here /usr/bin/ld: target/vw_jni.a: .preinit_array section is not allowed in DSO /usr/bin/ld: failed to set dynamic section sizes: Nonrepresentable section on output collect2: error: ld returned 1 exit status

I'm not sure what this means and when I search around for it find results such as "C program no longer compiles in Ubuntu" that seem to suggest that I forgot a -o flag, but I know I have not.

  1. Is what I'm trying to do possible?
  2. What am I doing wrong?

I'm doing this on a Docker instance obtained through docker pull ubuntu:14.04

UPDATE:

I'm able to get rid of a few of the errors with the following command line

/usr/bin/g++ -shared -std=c++0x -D__extern_always_inline=inline -Wall -pedantic -O3 -fomit-frame-pointer -fno-strict-aliasing -D_FILE_OFFSET_BITS=64 -DNDEBUG -fPIC -nostdlib -Wl,--whole-archive target/vw_jni.a -o target/vw_jni.lib

This generates the following output

/usr/bin/ld: warning: Cannot create .note.gnu.build-id section, --build-id ignored. /usr/bin/ld: target/vw_jni.a: .preinit_array section is not allowed in DSO /usr/bin/ld: failed to set dynamic section sizes: Nonrepresentable section on output collect2: error: ld returned 1 exit status

The reason I think this works is that by excluding the standard lib I don't have the redefinitions. I'm not sure where to go from here though.

2

There are 2 answers

5
Basile Starynkevitch On

This is practically not wise, because if you put the object files extracted from some static library these object files still remain position dependent code.

Shared libraries should very preferably contain position independent code (because the dynamic linker ld-linux.so is mmap-ing segments inside the .so at some random address, e.g. because of ASLR), otherwise the dynamic linker would have to process a big lot of relocations (so dynamic linking becomes very inefficient).

So even if you succeed to convert your static library into a shared one, it won't be wise to do so.

So keep your static library as is, or recompile their source code with -fPIC to build a shared object.

0
greyblue9 On

I think the problem here is with the command line you're using. The flags --whole-archive and --no-whole-archive apply to all subsequent arguments on the command line, which includes a number of standard libraries and object files (e.g., -lc, crt0.o, libc_nonshared.a, etc.) that are automatically appended behind the scenes.

If there's no --no-whole-archive switch directly after the filenames of static libraries you intend to bring in, this will also apply --whole-archive to the built-in archives that come after your last argument, e.g., it will try to also bring in every object from libc.a, libm.a, etc. which will at the very least fail with a "multiple definition" error. Try adding --no-whole-archive switch to your command line directly after target/vw_jni.a so you end up with something like:

/usr/bin/g++ -shared -std=c++0x   -D__extern_always_inline=inline -Wall -pedantic -O3 \
  -fomit-frame-pointer -fno-strict-aliasing  -D_FILE_OFFSET_BITS=64 -DNDEBUG -fPIC \
  -Wl,--whole-archive target/vw_jni.a -Wl,--no-whole-archive \
  -o target/vw_jni.lib