我们最近被要求发布我们其中一个库的 Linux 版本,之前我们是在 Linux 下开发并为 Windows 发布的,在 Windows 中部署库通常要容易得多。我们遇到的问题是将导出的符号剥离为仅暴露界面中的符号。想要这样做有三个很好的理由
- 保护我们技术的专有方面不通过导出的符号暴露。
- 防止用户遇到符号名称冲突的问题。
- 加快图书馆的加载速度(至少我被告知)。
那么举个简单的例子:
测试.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
并检查符号
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 共享库中删除所有不必要的符号(不属于公开库功能的 IE 符号)?我已经为 g++ 和 ld 尝试了很多选项,但收效甚微,所以我更喜欢已知有效的答案而不是相信的答案。
尤其是:
- 来自(闭源)静态库的符号不会被导出。
- 标准库中的符号不会被导出。
- 目标文件中的非公共符号不会被导出。
我们导出的接口是C。
我知道关于 SO 的其他类似问题:
但在答案方面收效甚微。