我们最近被要求为我们的一个库发布Linux版本,之前我们在Linux下开发并发布了Windows版本,其中在Windows下部署库通常更容易。我们遇到的问题是将导出的符号剥离到仅包含公开接口中的符号。有三个很好的原因想要这样做:
显然不足。因此,接下来我们将重新声明公共函数为。
注意:启用优化后,您需要确保向量实际被使用,以便编译器不会将未使用的符号优化掉。
我相信我的同事已经成功构建了一个临时解决方案,涉及版本文件和修改STL头文件(!) ,它似乎可以工作,但我想问一下:
是否有一种干净的方法可以从Linux共享库中删除所有不必要的符号(即不属于公开库功能的符号)? 我尝试了很多g++和ld选项,但成功率很低,因此我更喜欢已知可行的答案而不是可能的答案。
特别是:
1.来自(闭源)静态库的符号没有被导出。
2.标准库的符号没有被导出。
3.来自对象文件的非公共符号没有被导出。
我们的导出接口是C。
我知道SO上的其他类似问题:
1.NOT sharing all classes with shared library 2.How to REALLY strip a binary in MacOs 3.GNU linker: alternative to --version-script to list exported symbols at the command line? 但是对答案的成功率很低。
- 保护我们技术中专有的方面不通过导出符号泄露。
- 防止用户出现冲突的符号名称问题。
- 加快库的加载速度(至少我是这么说的)。
test.cpp
#include <cmath>
float private_function(float f)
{
return std::abs(f);
}
extern "C" float public_function(float f)
{
return private_function(f);
}
使用(g++ 4.3.2,ld 2.18.93.20081009)编译
g++ -shared -o libtest.so test.cpp -s
使用{{ inspect }}检查符号
nm -DC libtest.so
提供
w _Jv_RegisterClasses
0000047c T private_function(float)
000004ba W std::abs(float)
0000200c A __bss_start
w __cxa_finalize
w __gmon_start__
0000200c A _edata
00002014 A _end
00000508 T _fini
00000358 T _init
0000049b T public_function
显然不足。因此,接下来我们将重新声明公共函数为。
extern "C" float __attribute__ ((visibility ("default")))
public_function(float f)
并编译使用
g++ -shared -o libtest.so test.cpp -s -fvisibility=hidden
这提供了
w _Jv_RegisterClasses
0000047a W std::abs(float)
0000200c A __bss_start
w __cxa_finalize
w __gmon_start__
0000200c A _edata
00002014 A _end
000004c8 T _fini
00000320 T _init
0000045b T public_function
这很好,除了std::abs被暴露出来。更麻烦的是当我们开始链接其他(静态)库时,这些库中使用的所有符号都会被导出。此外,当我们开始使用STL容器时:
#include <vector>
struct private_struct
{
float f;
};
void other_private_function()
{
std::vector<private_struct> v;
}
我们最终会从C++库中获得许多额外的导出项。
00000b30 W __gnu_cxx::new_allocator<private_struct>::deallocate(private_struct*, unsigned int)
00000abe W __gnu_cxx::new_allocator<private_struct>::new_allocator()
00000a90 W __gnu_cxx::new_allocator<private_struct>::~new_allocator()
00000ac4 W std::allocator<private_struct>::allocator()
00000a96 W std::allocator<private_struct>::~allocator()
00000ad8 W std::_Vector_base<private_struct, std::allocator<private_struct> >::_Vector_impl::_Vector_impl()
00000aaa W std::_Vector_base<private_struct, std::allocator<private_struct> >::_Vector_impl::~_Vector_impl()
00000b44 W std::_Vector_base<private_struct, std::allocator<private_struct> >::_M_deallocate(private_struct*, unsigned int)
00000a68 W std::_Vector_base<private_struct, std::allocator<private_struct> >::_M_get_Tp_allocator()
00000b08 W std::_Vector_base<private_struct, std::allocator<private_struct> >::_Vector_base()
00000b6e W std::_Vector_base<private_struct, std::allocator<private_struct> >::~_Vector_base()
00000b1c W std::vector<private_struct, std::allocator<private_struct> >::vector()
00000bb2 W std::vector<private_struct, std::allocator<private_struct> >::~vector()
注意:启用优化后,您需要确保向量实际被使用,以便编译器不会将未使用的符号优化掉。
我相信我的同事已经成功构建了一个临时解决方案,涉及版本文件和修改STL头文件(!) ,它似乎可以工作,但我想问一下:
是否有一种干净的方法可以从Linux共享库中删除所有不必要的符号(即不属于公开库功能的符号)? 我尝试了很多g++和ld选项,但成功率很低,因此我更喜欢已知可行的答案而不是可能的答案。
特别是:
1.来自(闭源)静态库的符号没有被导出。
2.标准库的符号没有被导出。
3.来自对象文件的非公共符号没有被导出。
我们的导出接口是C。
我知道SO上的其他类似问题:
1.NOT sharing all classes with shared library 2.How to REALLY strip a binary in MacOs 3.GNU linker: alternative to --version-script to list exported symbols at the command line? 但是对答案的成功率很低。