在没有 -fPIC 的情况下将静态库链接到共享库
我想将目标文件和静态库合并到一个共享库中,但静态库不应暴露,它只在进入共享库的目标文件中引用.我认为在这种情况下,我不需要使用 -fPIC
编译静态库,但我不知道如何告诉链接器我不会使用静态库中的符号这一事实.为了说明我的问题,请使用以下文件:
I want to combine object files and a static library into a shared library but the static library shall not be exposed, it is only referred in the object files that go into the shared library. I think that in this case, I do not need to compile the static library with -fPIC
but I do not know how to tell the linker that the fact that I will not use the symbols from the static library. As an illustration of my problem, take the following files:
文件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
问题:如何调整最后一个命令,以免出现错误?这可能吗?
Question: How can I adjust the last command such I do not get an error? Is this possible?
注意我不想编译 static.cpp
with -fPIC
我不需要共享库中的符号(这里 return_static_version_info()
).
推荐答案
你不能(或者至少你不应该)将静态库链接到共享库.
You cannot (or at least you should not) link a static library into a shared library.
即使您碰巧成功地将非 PIC 静态库 libX.a
链接到共享库 libY.so
,结果也不会与位置无关的代码(因此会有很多无用"或烦人"的重定位).
Even if you happen to apparently succeed in linking a non-PIC static library libX.a
into a shared library libY.so
, the resulting thing won't have position-independent code (so would have a lot of "useless" or "annoying" relocations).
共享库只需要包含与位置无关的代码(在实践中);但静态库不包含 PIC.
A shared library needs to contain only position-independent code (in practice); but a static library does not contain PIC.
我不想用 -fPIC 编译 static.cpp
I do not want to compile static.cpp with -fPIC
但你真的应该这样做.
阅读 Drepper 的 如何编写共享库了解详情.
Read Drepper's How to Write Shared Libraries for details.
顺便说一句,一些 Linux 发行版(例如 Debian)提供了一个 libc6-pic
包,其中提供了诸如 /usr/lib/x86_64-linux-gnu/libc_pic.a
之类的文件这是一个与位置无关的代码的静态库.这可能用于扩展系统的 libc.so.6
,例如您自己的函数(或您自己的 malloc
等...).
BTW, some Linux distributions (e.g. Debian) provide a libc6-pic
package giving files such as /usr/lib/x86_64-linux-gnu/libc_pic.a
which are a static library of position-independent code. This might be used to extend your system's libc.so.6
with e.g. your own function (or your own malloc
, etc...).
在实践中,你最好用-fPIC
重新编译你的静态库代码;顺便说一句,x86-64 ISA 旨在促进 PIC.
In practice, you'll better recompile your static library code with -fPIC
; BTW the x86-64 ISA was designed to facilitate PIC.
最后,如果您关心优化,还有 很多其中.您是否考虑过使用 gcc -O3 -fPIC -flto
进行编译和链接?在某些情况下,您可能会考虑使用 -ffast-math
(它可以针对 C 标准进行优化),或者将 -O3
替换为 -Ofast
.
At last, if you care about optimizations, there are many of them. Did you consider compiling and linking with gcc -O3 -fPIC -flto
? In some cases, you might consider -ffast-math
(which enables optimizations against the C standard), or replacing -O3
with -Ofast
.
您当然应该使用最近的 GCC 或 Clang 编译器(或最近的专有 icc
).这个老问题(在您的评论中提到)大约是 4.7.2018 年秋季的当前 GCC 是 GCC 8 和 GCC 9 正在开发中(因此应该在 2019 年春季出现).当前的 Clang 是 Clang 7.编译器在优化方面不断取得进展.
And you surely should use a recent GCC or Clang compiler (or a recent proprietary icc
). This old question (mentioned in your comments) is about 4.7. Current GCC in fall 2018 is GCC 8, and GCC 9 is worked upon (so should appear in spring 2019). Current Clang is Clang 7.
Compilers are continuously making progress on optimizations.
您可能想要下载最新版本的 GCC 或 Clang 的 source 压缩包,然后在您的计算机上构建它.这是获得这些编译器最新版本的好方法,因为发行版制造商通常更喜欢它们的旧版本(即使与不符合标准的代码也兼容).
You might want to download the source tarball of the latest release of GCC or of Clang and build that on your computer. This is a good way to have a recent version of these compilers, since distribution makers often prefer an older variant of them (which is compatible even with non-standard compliant code).
相关文章