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

Turning a statically linked library into a dynamic one

本文关键字:动态链接库 转换 静态 链接      更新时间:2023-10-16

我知道这个问题已经被问过几次了,但是没有一个解决方案对我有效。我有一个静态链接库,我想与Java 8之前版本的JNI层一起使用。根据我阅读的"如何在gcc中将静态库链接到动态库",这似乎是可能的。下面是我的命令行:

/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

这是基于编写一个JNI层到wwpal rabbit库。

在构建过程中,我已经通过静态链接静态地创建了一个名为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

我不确定这意味着什么,当我搜索它时,发现诸如"C程序不再在Ubuntu中编译"之类的结果似乎表明我忘记了-o标志,但我知道我没有。

  1. 我想做的是可能的吗?
  2. 我做错了什么?

我在通过docker pull ubuntu:14.04

获得的Docker实例上这样做更新:

我可以用下面的命令行

消除一些错误

/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

生成以下输出

/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

我认为这有效的原因是通过排除标准库,我没有重新定义。我不知道该怎么做

我认为这里的问题是您使用的命令行。标志--whole-archive--no-whole-archive应用于命令行上的所有后续参数,其中包括许多自动附加在后台的标准库和目标文件(例如,-lc, crt0.o, libc_nonshared.a等)。

如果在你打算引入的静态库的文件名之后没有直接的--no-whole-archive开关,这也会将--whole-archive应用于你最后一个参数之后的内置存档,例如,它会尝试从libc.a, libm.a等中引入每个对象,这至少会失败,导致"多重定义"错误。尝试将--no-whole-archive switch直接添加到target/vw_jni.a之后的命令行中,这样您最终会得到如下内容:

/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

这实际上是不明智的,因为如果你把从一些静态库中提取的目标文件,这些目标文件仍然是位置相关的代码。

共享库最好包含位置无关的代码(因为动态链接器ld-linux.sommap -在.so内的一些随机地址,例如,因为ASLR),否则动态链接器将不得不处理大量的重定位(因此动态链接变得非常低效)。

因此,即使您成功地将静态库转换为共享库,这样做也是不明智的。

所以保持你的静态库不变,或者用-fPIC重新编译它们的源代码来构建一个共享对象。