在没有-fPIC的情况下将静态库链接到共享库

时间:2018-10-31 15:12:41

标签: c++ linker g++ libtool

我想将目标文件和静态库组合到共享库中,但是静态库不应公开,它仅在进入共享库的对象文件中被引用。我认为在这种情况下,我不需要使用-fPIC编译静态库,但是我不知道如何告诉链接器我不会使用静态库中的符号这一事实。为了说明我的问题,请获取以下文件:

文件foo.cpp

#include "static.h"
using namespace std;

string version_info()
{
    return static_version_info();
}

文件static.cpp

#include"static.h"
#include <vector>
using namespace std;
string static_version_info()
{
    std::vector<int> ivec;
    return to_string(ivec.size());
}

文件static.h

#ifndef STATIC_H
#define STATIC_H
#include<iostream>
using namespace std;
std::string static_version_info();
#endif 

然后做

$ g++ -c foo.cpp -o foo.o -fPIC
$ g++ -c static.cpp -o static.o
$ gcc-ar rcs static.a static.o
$ g++ -shared foo.o static.a
/usr/bin/ld: static.a(static.o): relocation R_X86_64_PC32 against symbol `_ZNSt6vectorIiSaIiEEC1Ev' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value
collect2: error: ld returned 1 exit status

问题: 如何调整上一个命令,这样我不会出现错误?这可能吗?

请注意,我不想使用 static.cpp 进行编译 -fPIC ,并且我不需要符号(此处 return_static_version_info() )。

1 个答案:

答案 0 :(得分:2)

您不能(或者至少您不应该)将静态库链接到共享库

即使您似乎成功地将非PIC静态库libX.a链接到共享库libY.so,所得到的东西也将没有位置无关的代码(因此会有很多“无用”或“烦人”的重定位)。

共享库只需要包含与位置无关的代码(实际上);但是静态库不包含PIC。

  

我不想用-fPIC编译static.cpp

但是你真的应该。

有关详细信息,请阅读Drepper的How to Write Shared Libraries

顺便说一句,某些Linux发行版(例如Debian)提供了一个libc6-pic软件包,提供了/usr/lib/x86_64-linux-gnu/libc_pic.a之类的文件,这些文件是与位置无关的代码的静态库。这可以用来扩展系统的libc.so.6,例如您自己的功能(或您自己的malloc等)。

在实践中,您最好使用-fPIC重新编译静态库代码; BTW x86-64 ISA旨在促进PIC。

最后,如果您关心优化,则有many个。您是否考虑过使用gcc -O3 -fPIC -flto进行编译和链接?在某些情况下,您可能会考虑使用-ffast-math(可针对C标准进行优化),或将-O3替换为-Ofast

您当然应该使用最新的GCC或Clang编译器(或最新的专有icc)。 This old问题(在您的评论中提到)约为4.7。当前在2018年秋季发布的GCC为GCC 8,并且GCC 9正在开发中(因此应该在2019年春季发布)。当前Clang是Clang 7。 编译器在优化方面不断取得进步。

您可能要下载最新版本的GCC或Clang的 source tarball,并在计算机上进行构建。这是拥有这些编译器最新版本的好方法,因为发行商通常更喜欢它们的较旧版本(即使与非标准兼容代码兼容)。