在没有 -fPIC 的情况下将静态库链接到共享库
Linking a static library into a shared library without -fPIC
我想将目标文件和静态库合并成一个共享库,但是静态库不能暴露,它只在进入共享库的目标文件中引用。我认为在这种情况下,我不需要使用 -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
and我不需要共享库中的符号(此处 return_static_version_info()
)。
你不能(或者至少你不应该)link一个静态库变成一个共享库.
即使您碰巧显然成功地将非 PIC 静态库 libX.a
转换为共享库 libY.so
,结果也不会与位置无关代码(因此会有很多 "useless" 或 "annoying" 重定位)。
共享库只需要包含与位置无关的代码(实际上);但是静态库不包含 PIC。
I do not want to compile static.cpp with -fPIC
但你真的应该这样做。
阅读 Drepper 的 How to Write Shared Libraries 了解详细信息。
顺便说一句,一些 Linux 发行版(例如 Debian)提供了一个 libc6-pic
包,其中包含诸如 /usr/lib/x86_64-linux-gnu/libc_pic.a
之类的文件,它们是位置无关代码的静态库。这可能用于扩展系统的 libc.so.6
,例如您自己的功能(或您自己的 malloc
,等等...)。
实际上,您最好使用 -fPIC
重新编译您的静态库代码;顺便说一句,x86-64 ISA 旨在促进 PIC。
最后,如果您关心优化,有 many 个。您是否考虑过编译 linking 和 gcc -O3 -fPIC -flto
?在某些情况下,您可能会考虑 -ffast-math
(启用针对 C 标准的优化),或将 -O3
替换为 -Ofast
。
而且您肯定应该使用最新的 GCC 或 Clang 编译器(或最新的专有 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。
编译器在优化方面不断取得进展。
您可能想要下载最新版本的 GCC 或 Clang 的 source tarball 并在您的计算机上构建它。这是拥有这些编译器的最新版本的好方法,因为发行版制造商通常更喜欢它们的旧变体(即使与非标准兼容代码也兼容)。
我想将目标文件和静态库合并成一个共享库,但是静态库不能暴露,它只在进入共享库的目标文件中引用。我认为在这种情况下,我不需要使用 -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
and我不需要共享库中的符号(此处 return_static_version_info()
)。
你不能(或者至少你不应该)link一个静态库变成一个共享库.
即使您碰巧显然成功地将非 PIC 静态库 libX.a
转换为共享库 libY.so
,结果也不会与位置无关代码(因此会有很多 "useless" 或 "annoying" 重定位)。
共享库只需要包含与位置无关的代码(实际上);但是静态库不包含 PIC。
I do not want to compile static.cpp with -fPIC
但你真的应该这样做。
阅读 Drepper 的 How to Write Shared Libraries 了解详细信息。
顺便说一句,一些 Linux 发行版(例如 Debian)提供了一个 libc6-pic
包,其中包含诸如 /usr/lib/x86_64-linux-gnu/libc_pic.a
之类的文件,它们是位置无关代码的静态库。这可能用于扩展系统的 libc.so.6
,例如您自己的功能(或您自己的 malloc
,等等...)。
实际上,您最好使用 -fPIC
重新编译您的静态库代码;顺便说一句,x86-64 ISA 旨在促进 PIC。
最后,如果您关心优化,有 many 个。您是否考虑过编译 linking 和 gcc -O3 -fPIC -flto
?在某些情况下,您可能会考虑 -ffast-math
(启用针对 C 标准的优化),或将 -O3
替换为 -Ofast
。
而且您肯定应该使用最新的 GCC 或 Clang 编译器(或最新的专有 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。
编译器在优化方面不断取得进展。
您可能想要下载最新版本的 GCC 或 Clang 的 source tarball 并在您的计算机上构建它。这是拥有这些编译器的最新版本的好方法,因为发行版制造商通常更喜欢它们的旧变体(即使与非标准兼容代码也兼容)。