如何在Linux/gcc上创建与pthreads和libstdc ++静态链接的共享对象?
在我回答你所描述的问题之前,我会注意到你最终想要实现的目标并不完全清楚,而且你的问题可能有更好的解决方案.
这就是说 - 尝试做你所描述的事情有两个主要问题:
其一是,你将需要分解libpthread
和libstdc++
他们与取得的目标文件.这是因为ELF二进制文件(在Linux上使用)有两个级别的"运行时"库加载 - 即使可执行文件是静态链接的,加载程序也必须在执行时加载二进制文件中的静态链接库,并映射正确的内存地址.这是在动态加载(共享对象)并映射到共享内存的库的共享链接之前完成的.因此,共享对象不能与这些库静态链接,因为在加载对象时,已经加载了所有静态链接库.这是链接静态库和普通对象文件之间的一个区别 - 静态库不仅像任何目标文件一样粘在可执行文件中,而且还包含在加载时引用的单独表. (我相信这与MS-DOS和经典Windows .LIB
文件中更简单的静态库形成鲜明对比,但对于那些可能比我记忆的更多).
当然,你实际上并不具有分解libpthread
和libstdc++
,你可以只使用建造它们时所产生的目标文件.收集它们可能有点困难(查找这些库的最终Makefile规则引用的对象).而且您必须ld
直接使用而不是gcc
/ g++
链接,以避免与动态版本链接.
第二个问题是重要的.如果您执行上述操作,您将确保拥有您要求构建的共享对象/动态库.但是,它不会非常有用,因为一旦您尝试将使用那些libpthread
/ libstdc++
(后者是任何C++程序)的常规可执行文件与此共享对象链接,它将失败并出现符号冲突 - 静态libpthread
/ libstdc++
对象的符号链接您的共享对象将与该可执行文件的标准libpthread
/ libstdc++
使用的符号冲突,无论它是否与标准库动态或静态链接.
你当然可以再尝试无论是隐藏所有的符号从静态对象libstdc++
/ libpthread
你的共享库使用,让他们在某些方面的私人,或者他们在联动自动重命名,这样就不会有冲突.但是,即使你得到那个工作,你会发现在运行一些不需要的结果,因为这两个libstdc++
/ libpthread
保持相当多的国家在全局变量和结构,你现在将不得不重复的和互不知晓对方的.这将导致这些全局数据与底层操作系统状态(如文件描述符和内存边界)之间的不一致(可能还有标准C库中的某些值,例如errno
for libstdc++
,以及信号处理程序和定时器)libpthread
.
为了避免过于宽泛的解释,我将添加了一句话:有时有可能是明智的理由为希望对连这样基本的库静态链接的libstdc++
,甚至libc
,即使它正变得越来越难以与近期系统的版本有点这些库(由于与加载器的一点耦合和使用的特殊链接器技巧),它绝对是可能的 - 我做了几次,并且知道其他情况仍然完成. 但是,在这种情况下,您需要静态链接整个可执行文件.与标准库的静态链接与其他对象的动态链接通常是不可行的.
编辑:我忘记提及的一个问题,但重要的是要考虑C++特定.遗憾的是,C++不适用于对象链接和加载的经典模型(在Unix和其他系统上使用).这使得C++中的共享库不是真正可移植的,因为很多东西如类型信息和模板在对象之间没有干净的分离(通常在编译时从头文件中获取大量实际的库代码) ). libstdc++
由于这个原因与GCC紧密结合,并且使用一个版本的g++
遗嘱编译的代码通常仅与libstdc++
from(与此非常相似)版本一起使用g++
.您肯定会注意到,如果您尝试使用GCC 4构建程序,并且系统上使用GCC 3构建任何非平凡的库,则不仅如此libstdc++
.如果您想要这样做的原因是试图确保您的共享对象始终与特定版本链接libstdc++
并且libpthread
它是针对它构建的,那么这将无济于事,因为使用不同/不兼容的程序libstdc++
也将使用不兼容的C++编译器或版本g++
,因此无论如何都无法与您的共享对象链接,除了实际的libstdc++
冲突.
如果你想知道"为什么这不是更简单?",一般的反思值得深思:让C++与动态/共享库很好地配合(意味着编译器之间的兼容性,以及用兼容的另一个版本替换动态库的能力)接口没有重建使用它的所有东西),不仅需要编译器标准化,而是在操作系统的加载器级别,对象和库文件的结构和接口以及链接器的工作需要显着扩展到相对的用于本机构建代码的常见操作系统上使用的简单Unix经典(Microsoft Windows,基于Mach的系统和NeXTStep亲属,如Mac OS,VMS亲属和一些大型机系统)今天.链接器和动态加载器需要知道诸如模板和键入之类的东西,在某种程度上具有小编译器的功能,以实际将库的代码调整为给定的类型 - 并且(这里是个人主观观察)似乎更高级别的中间中间代码(与更高级别的语言和即时编译一起)比本机对象格式和链接器的扩展更快,并且可能更快地标准化.