将共享库与静态库链接:静态库的编译方式必须与应用程序链接它的方式不同吗?

至少在Linux和Solaris上,静态库实际上只是一堆编译好的.o文件被扔进一个大文件中。 编译静态库时,通常会忽略-fpic标志,因此生成的代码与位置有关。

现在说我的静态库是B.我已经构建了它并且得到了.a文件,它实际上只是所有位置相关的.o文件的全局。 现在我有一个我想构建的共享库,A,我希望它静态链接B.当我构建A时,我自然会使用-fpic标志使生成的代码位置独立。 但是,如果我链接B,我不是混合位置依赖和位置独立的目标文件?

除非我还指定-mimpure-text,否则我会收到很多文本重定位错误,我认为这可能是原因。 看来,当我编译一个库时,我真的需要编译它3次,共享版本,静态版本和静态 – 可以使用的共享库版本。 我对吗? 我可以继续使用-mimpure-text但g ++手册页说如果你这样做,对象实际上并没有最终被共享(不清楚它是否全部未被共享,或者仅仅是静态链接的部分,有人知道吗?) 。

您不必在共享对象中使用PIC代码(因为您发现可以使用-mimpure-text选项来允许)。

也就是说,共享对象中的非PIC代码更重量级。 使用PIC代码,内存中的文本页面只是磁盘上文本页面的直接内存映射。 这意味着如果多个进程正在使用共享对象,则它们可以共享内存页面。

但是,如果您没有PIC代码,则当运行时链接程序加载共享对象时,它必须将修正应用于文本页面。 这意味着使用共享对象的每个进程都将拥有其自身唯一版本的任何文本页面,该文本页面上有一个修复程序(即使共享对象加载到与写入时复制相同的地址,也只注意到该页面是修改,而不是以相同的方式修改)。

对我来说,重要的问题是你是否会同时运行多个进程,每个进程都加载共享对象。 如果你这样做,绝对值得确保SO中的所有代码都是PIC。

但如果情况并非如此,并且只有一个进程加载了共享对象,那么它就不那么重要了。

我在链接阶段为静态库的共享对象库版本执行以下操作:g ++ -shared -o libshared.so -Wl, – whole-archive -fPIC -lstatic -Wl, – no-whole-archive。 由于–whole-archive链接(列表)静态库(forms为libstatic.a)中的每个对象,我相信在(list)之前使用-fPIC是所有OP需要做的。

作为一种替代方法,运送两个库:您的共享库和您正在链接的静态库。 它们应该正确链接到最终的可执行文件。