简体   繁体   English

将静态链接库转变为动态库

[英]Turning a statically linked library into a dynamic one

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.我有一个静态链接库,我想将它与 Java 8 之前版本的 JNI 层一起使用。根据我对“如何将静态库链接到 gcc 中的动态库”的阅读,这似乎是可能的。 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.这是基于将 JNI 层写入Vowpal Wabbit库。

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的文件

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.我不确定这是什么意思,当我四处搜索时,发现诸如“C 程序不再在 Ubuntu 中编译”之类的结果似乎表明我忘记了-o标志,但我知道我没有。

  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我正在通过docker pull ubuntu:14.04获得的 Docker 实例上执行此操作

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.我不知道从这里去哪里。

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 (eg, -lc , crt0.o , libc_nonshared.a , etc.) that are automatically appended behind the scenes.标志--whole-archive--no-whole-archive适用于命令行上的所有后续参数,其中包括许多标准库和目标文件(例如, -lccrt0.olibc_nonshared.a等.) 自动附加在幕后。

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, eg, 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.如果在您打算引入的静态库的文件名之后没有--no-whole-archive开关,这也将应用于--whole-archive到您最后一个参数之后的内置档案,例如,它将尝试从libc.alibm.a等中引入每个对象, libc.a对象至少会因“多重定义”错误而失败。 Try adding --no-whole-archive switch to your command line directly after target/vw_jni.a so you end up with something like:尝试在target/vw_jni.a之后直接将--no-whole-archive开关添加到命令行,这样您最终会得到如下结果:

/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

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, eg because of ASLR), otherwise the dynamic linker would have to process a big lot of relocations (so dynamic linking becomes very inefficient).共享库最好包含位置无关代码(因为动态链接器ld-linux.so.so中某个随机地址处的mmap -ing 段,例如因为 ASLR),否则动态链接器将不得不处理大量重定位(因此动态链接变得非常低效)。

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.所以保持你的静态库原样,或者用-fPIC重新编译它们的源代码来构建一个共享对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM