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

3
我希望将目标文件和静态库合并成一个共享库,但不希望静态库被公开,只在进入共享库的目标文件中引用。我认为在这种情况下,我不需要使用-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

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

请注意,我不想使用 -fPIC 编译 static.cpp , 我也不需要在共享库中使用符号 (这里是 return_static_version_info())。


我不明白你的思路。如果你“...不会使用静态库中的符号...”,为什么还需要将其链接? - SergeyA
@SergeyA 静态库仅在与静态库链接在一起的目标文件中定义的接口中使用。我只通过这个接口访问静态库。问题是,在这种情况下,我是否可以避免为静态库使用-fPIC - phinz
1个回答

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

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

共享库需要仅包含位置无关代码(在实践中);但静态库不包含PIC。

我不想使用 -fPIC 编译 static.cpp

但您确实应该这样做。

有关详细信息,请阅读Drepper的 如何编写共享库

顺便提一下,一些Linux发行版(例如Debian)提供了一个libc6-pic包,其中包含诸如/usr/lib/x86_64-linux-gnu/libc_pic.a之类的位置无关代码的静态库。这可能用于扩展您系统的libc.so.6,例如使用您自己的函数(或您自己的malloc等)。

实际上,最好使用-fPIC重新编译您的静态库代码;顺便说一句,x86-64 ISA旨在促进PIC。

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

您应该使用最新的GCC或Clang编译器(或最新的专有icc)。这篇旧文章(在您的评论中提到)是关于4.7版本的。2018年秋季,当前的GCC是GCC 8GCC 9正在开发中(因此应在2019年春季出现)。当前的Clang是Clang 7

编译器不断地在优化方面取得进展。

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


当然我可以使用fPIC,但我不想减慢静态库中高性能代码的速度。 我认为如果我不需要来自外部(使用共享库时)的位置无关代码,仅通过在使用-fPIC 编译的目标文件中定义的接口,那么避免使用-fPIC 是可以的。所以这不是真的吗?即使对于静态库,其函数不会直接从共享库的用户中调用,我仍然需要它吗? - phinz
3
你确定在x86-64架构上使用 -fPIC 会减慢代码速度吗?你进行过基准测试吗?这种减速的程度是多少?x86-64指令集架构旨在方便使用位置独立代码。 - Basile Starynkevitch
不,但我了解到-fPIC会禁用一些优化。是的,我知道在基准测试之前不应该尝试进行优化... - phinz
你在哪里看到的?是为了什么ISA?我倾向于相信你的消息来源是错误的。 - Basile Starynkevitch
https://dev59.com/LmUo5IYBdhLWcg3wpg_N 的第二个答案。 - phinz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接