如何使用静态库(.a文件)而不是一组目标文件(.o)来创建共享库

时间:2014-09-05 15:39:37

标签: c++ g++ linker-errors

我有一个共享库,我用它来创建一个可执行的二进制文件。我只能控制库的构建过程和可执行的二进制文件,而不是所涉及的源文件。正如所料,可执行二进制文件中的源文件引用了库中的许多函数。

目前,共享库是直接使用objectfiles(.o)构建的。

g++ -shared ${OBJECT_FILES} -o ${SHARED_LIBRARY}

我想通过将它们分组到静态库(.a文件或achive)中来发布目标文件。

为了节省空间,我在创建存档文件时删除了所有.o文件。所以现在,构建命令是

g++ -shared ${ACRCHIVE_FILE} -o ${SHARED_LIBRARY}

图书馆建设很好 但是,当我尝试通过链接到此共享库来构建可执行二进制文件时,未定义二进制文件所指示的符号,并且无法链接。 (未定义的Context::Get()引用)

根据我的理解,如果我们直接使用.o文件创建共享库或者包含所有.o文件的存档,这应该无关紧要,但显然要么不可能,要么我可能会遗漏某些内容。

1 个答案:

答案 0 :(得分:2)

共享库libfoo.so应包含PIC代码,静态库libfoo.a包含普通的非PIC代码。因此,您无法从静态库创建共享库。

共享库需要位置无关代码,因为它们的段mmap(2) - 几乎是任意和可变的地址 - 没有MAP_FIXED ...还ASLR

原则上你可以从PIC目标文件构建一个静态库,但实际上没有人这样做。

你可能(如果你真的坚持)制作一个由非PIC代码组成的ELF共享对象,但结果会有非常糟糕的表现;动态链接器会有很多relocations,因此大多数段都不会被共享,动态链接会非常慢。

将共享库的foo.cc编译为PIC对象文件foo.pic.o

g++ -Wall -c -O foo.cc  -fPIC -o foo.pic.o

为静态库编译一个普通的非PIC对象文件foo.o

g++ -Wall -c -O foo.cc -o foo.o 

foo.pic.o个共享库中将bar.pic.olibfoobar.so的共享库转换为libdep.so个链接:

g++ -shared foo.pic.o bar.pic.o -ldep -o libfoobar.so

在制作上述共享库时,您经常需要添加更多链接选项,例如-Wl,-rpath, ...或-Wl,-soname, ....

BTW,无法将归档libfoobar.a(即使它由PIC文件组成)链接到libfoobar.so,因为没有名称未定义,并且需要链接来自{{1的一些目标文件(或许您可以尝试使用libfoobar.a取消定义某个符号symb,但我不建议这样做)。

-u symbfoo.o的静态库转换为bar.o

libfoobar.a

请注意,ranlib(创建归档的索引)不再需要,因为GNU ar cv libfoobar.a foo.o bar.o 完成了它的工作。

另请阅读ld.so(8)ldd(1)ld(1)ar(1)objdump(1)readelf(1)dlopen(3)(通常,您如果主程序在运行时加载ar - ed插件,则需要将主程序与-rdynamic链接,以使插件能够在主程序中找到一些符号。

注意:我只是构建一个共享库而不关心静态链接。请注意,在某些系统上,PIC的成本略高(代码稍大和/或较慢)。 AFAIK,PIC开销在x86-64上的成本低于32位Linux x86代码。在一些架构和ABI上,PIC可能具有可忽略的开销(或者甚至可能比非位置无关代码更有效)。

参考文献:Drepper's paper: How to Write Shared Libraries& Levine's book: Linkers and Loaders& Program Library HowTo