我有一个共享库,我用它来创建一个可执行的二进制文件。我只能控制库和可执行二进制文件的构建过程,而不能控制所涉及的源文件。正如预期的那样,可执行二进制文件中的源文件引用了库中的许多函数。
目前共享库是直接使用objectfiles(.o)构建的。
g++ -shared ${OBJECT_FILES} -o ${SHARED_LIBRARY}
我也想通过将目标文件分组到静态库(.a 文件或 achive)中来发布它们。
为了节省空间,我在创建存档文件时删除了所有 .o 文件。所以现在,构建命令是
g++ -shared ${ACRCHIVE_FILE} -o ${SHARED_LIBRARY}
该库构建良好。
但是,当我尝试通过链接到此共享库来构建可执行二进制文件时,二进制文件引用的符号未定义,因此无法链接。 (对 Context::Get() 的 undefined reference )
根据我的理解,如果我们直接使用 .o 文件或包含所有 .o 文件的存档创建共享库,应该没有关系,但显然这是不可能的,或者我可能会丢失一些东西。
最佳答案
共享库libfoo.so
应包含PIC代码和静态库 libfoo.a
包含普通的非 PIC 代码。因此您无法从静态库创建共享库。
共享库需要位置无关代码,因为它们的段是 mmap(2) -ed 在几乎任意和可变的地址 - 没有 MAP_FIXED
...另请参阅 ASLR .
原则上您可以从 PIC 目标文件构建静态库,但实际上没有人这样做。
你可以(如果你真的坚持)做一个 ELF由非PIC代码组成的共享对象,但结果会导致性能非常差;动态链接器会有很多 relocations ,因此大多数片段将不共享,并且动态链接会非常慢。
将共享库的foo.cc
编译为PIC目标文件foo.pic.o
:
g++ -Wall -c -O foo.cc -fPIC -o foo.pic.o
将其编译为静态库 int 普通非 PIC 目标文件 foo.o
:
g++ -Wall -c -O foo.cc -o foo.o
将foo.pic.o
和bar.pic.o
的共享库制作成libfoobar.so
链接到一些libdep.so
共享库:
g++ -shared foo.pic.o bar.pic.o -ldep -o libfoobar.so
在创建如上所述的共享库时,您通常希望添加更多链接选项,例如-Wl,-rpath,
... 或 -Wl,-soname,
....
顺便说一句,不可能将存档 libfoobar.a
(即使它是由 PIC 文件组成)链接到 libfoobar.so
,因为没有未定义的名称并需要从 libfoobar.a
链接一些目标文件(也许您可以尝试使用 -u symb
取消定义某些符号 symb
但我不这样做建议这样做)。
将foo.o
和bar.o
的静态库制作成libfoobar.a
:
ar cv libfoobar.a foo.o bar.o
请注意 ranlib (创建文件索引)不再需要,因为 GNU ar 完成了它的工作。
另请阅读ld.so(8) , ldd(1) , ld(1) , ar(1) , objdump(1) , readelf(1) , dlopen(3) (通常,如果主程序在运行时加载 dlopen
-ed 插件,则需要将主程序与 -rdynamic
链接,以使插件能够在主程序中查找某些符号) .
注意:我只会构建一个共享库,根本不关心静态链接。请注意,在某些系统上,PIC 具有轻微的成本(代码稍大和/或较慢)。据我所知,x86-64 上的 PIC 开销比 32 位 Linux x86 代码上的开销要低。在某些架构和 ABI 上,PIC 的开销可以忽略不计(或者甚至可能比非位置无关代码更有效)。
引用文献:Drepper's paper: How to Write Shared Libraries & Levine's book: Linkers and Loaders & Program Library HowTo
关于c++ - 如何使用静态库(.a 文件)而不是一组目标文件(.o)来创建共享库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25689480/