如何从静态库中剥离私有成员函数符号?
我希望能从静态库中剥离所有私有成员函数符号,我的类结构如下:
头文件
#define PUBLIC __attribute__ ((visibility ("default"))) #define LOCAL __attribute__ ((visibility ("hidden"))) namespace my_namespace { class my_class { public: PUBLIC my_class(); PUBLIC ~my_class(); PUBLIC void do_something(); private: LOCAL float internal_func(); LOCAL inline float inline_func(); float member_var_; }; }
cpp文件
namespace my_namespace { my_class::my_class(){member_var_ = 0;} // 省略其他构造/析构实现 void my_class::do_something(){ // 一些代码 member_var_ = internal_func(); member_var_ += inline_func(); } float my_class::internal_func() { // 一些代码 } inline float my_class::inline_func(){ // 一些代码 } }
实际代码更为复杂,包含大量函数和私有成员变量,且几乎每个函数都使用成员变量,因此无法将这些函数声明为static或从类中移除。
我已使用编译选项-fvisibility=hidden -fvisibility-inlines-hidden,其中inline相关选项对已内联的函数有效,但仍能在libmy_class.a文件中通过grep找到internal_func符号。使用GNU Strip的--strip-unneeded选项也无法移除该符号,仍能通过grep找到。我是否遗漏了什么?还是这些符号根本无法被剥离?
为什么静态库中的私有符号无法被strip --strip-unneeded移除?
静态库本质是目标文件(.o)的归档集合,strip --strip-unneeded只会移除目标文件中未被引用的符号。但你的internal_func被do_something直接调用,属于被引用的符号,因此strip不会将其移除——静态库需要保留这些符号,才能在后续链接可执行文件时完成符号解析。
另外,-fvisibility=hidden在静态库场景下的作用有限:这个选项主要影响动态库的符号导出,对于静态库,编译器默认会保留所有符号(无论可见性属性),因为静态库的符号是在链接阶段直接合并到可执行文件中的,可见性标记不会改变静态库中符号的留存逻辑。
可行的解决方法
段优化+链接时垃圾回收
编译时添加-ffunction-sections -fdata-sections,让每个函数/数据都放在独立的段中;后续将静态库链接为可执行文件或动态库时,添加链接选项-Wl,--gc-sections,链接器会自动移除未被导出的符号(标记为hidden的符号)。如果必须生成静态库,可结合链接时优化(LTO):编译时加-flto,打包静态库后用strip --strip-all(注意该选项会移除所有符号,需结合LTO规则保留公共符号)。匿名命名空间隐藏私有函数
把私有成员函数移到cpp文件内的匿名命名空间中,通过类指针访问成员变量,这样函数会成为静态符号,不会暴露到全局符号表:namespace my_namespace { namespace { float internal_func(my_class* obj) { return obj->member_var_ * 2; // 通过指针访问类成员 } } void my_class::do_something(){ member_var_ = internal_func(this); } }手动用
objcopy移除符号
逐个处理静态库中的目标文件,手动指定要移除的符号:# 提取静态库内的目标文件 ar x libmy_class.a # 移除指定符号 objcopy --strip-symbol=my_namespace::my_class::internal_func my_class.o # 重新打包静态库 ar crs libmy_class_new.a *.o
关键结论
静态库中被引用的私有函数符号无法通过常规strip --strip-unneeded移除,因为链接器依赖这些符号完成后续链接。必须通过段优化、LTO、符号隐藏技巧或手动修改目标文件的方式实现符号剥离。
内容的提问来源于stack exchange,提问作者Connagh Jacobi

