最近,我们被要求提供其中一个库的Linux版本,之前我们是在Linux下开发的,并已针对Windows发行,而在Windows上部署库通常要容易得多。我们遇到的问题是将导出的符号剥离为仅暴露界面中的符号。想要这样做的三个很好的理由
然后举一个简单的例子:
测试文件
#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共享库中剥离所有不必要的符号(即那些不是公开库功能的一部分的符号)? 我已经为g ++和ld尝试了很多选项,但收效甚微,因此,我宁愿选择已知有效的答案,而不是相信的答案。
特别是:
我们的导出接口是C。
因此,我们目前的解决方案如下:
#include <cmath> #include <vector> #include <typeinfo> struct private_struct { float f; }; float private_function(float f) { return std::abs(f); } void other_private_function() { std::vector<private_struct> f(1); } extern "C" void __attribute__ ((visibility ("default"))) public_function2() { other_private_function(); } extern "C" float __attribute__ ((visibility ("default"))) public_function1(float f) { return private_function(f); }
出口版本
LIBTEST { global: public*; local: *; };
用编译
g++ -shared test.cpp -o libtest.so -fvisibility=hidden -fvisibility-inlines-hidden -s -Wl,--version-script=exports.version
00000000 A LIBTEST w _Jv_RegisterClasses U _Unwind_Resume U std::__throw_bad_alloc() U operator delete(void*) U operator new(unsigned int) w __cxa_finalize w __gmon_start__ U __gxx_personality_v0 000005db T public_function1 00000676 T public_function2
这与我们正在寻找的相当接近。但是有一些陷阱:
我很高兴接受任何人提出的更好的解决方案!