提问人:umläute 提问时间:10/24/2023 更新时间:10/26/2023 访问量:44
构建后从 C++ 动态库中删除一组符号(仅保留给定的集合)
post-build removal of a set of symbols (keeping only a given set) from C++ dynamic library
问:
我正在构建一个动态库(在 C++ 中),它导出了许多符号。
这些导出的符号(显然)与我的库的 API 匹配。 但是,我的 lib 还导出了大量其他符号(我的公共标头中根本没有提到这些符号)。
为了保持我的库的二进制接口较小(防止名称冲突;不要破坏符号空间;防止库的使用者意外使用可能在下一个版本中消失的符号),我可以使用版本脚本使导出的符号显式,如下所示(实际上版本脚本要复杂得多;无论如何, 它涉及 C++ 去边形符号和通配符):
{
global:
extern "C++" {
/* the public API uses the 'MyLib::' namespace */
MyLib::*;
};
/* g++ version mangling prefixes for 'typeinfo' */
_ZTI*; _ZTF*; _ZTS*;
/* g++ version mangling prefixes for 'vtable' */
_ZTT*; _ZTV*;
local:
*;
};
然后使用这些附加标志调用链接器-fvisibility=hidden -Wl,--version-script=mylib.ver
凉。
现在,该库还附带了一个测试套件。 为了能够编写简洁的测试,单元测试使用不属于公共 API 的符号。
从库中剥离非公共符号将阻止单元测试(链接到库)找到这些符号。 因此,测试套件将变得不可用。
一个明显的解决方法是在单元测试中只使用公共符号。但这会使单元测试变得更加复杂,并且测试结果更难解释。
另一种可能的解决方案是不要使用动态库进行单元测试,而是使用其他库(例如静态库;或没有版本脚本链接的库的变体)。 我不喜欢这个,因为我想测试实际的库,而不是一些替代品。
第三种解决方案(我最喜欢的)是将非公共符号的剥离推迟到库的部署:测试套件将使用本地库构建(包含所有符号),但在(或其他一些明确的构建后步骤)中,不必要的符号被剥离。make install
不幸的是,我不知道如何实现这一点。
- version-script 是链接器的一项功能
- 像做一些不同的事情(有一个标志(GNU?)条应该删除一个符号,但它似乎不起作用,即使对于普通的C库(没有C++符号修改)
strip
-N
那么:有没有办法在构建后步骤中从库中删除符号(仅保留已知集合)? 如果是这样,如何使用 C++ 符号修改和使用通配符来做到这一点?
答:
有没有办法在构建后步骤中从库中删除符号(仅保留已知集合)?
是的。(动态)符号名称驻留在该部分中,如果覆盖其中的名称(例如,覆盖 ),动态链接器将无法解析这些符号。.dynstr
_ZMyLib...
_XMyLib
遍历(动态)符号表中的所有符号并不难。.dynsym
如何使用 C++ 符号修改和使用通配符来做到这一点?
您必须对每个符号调用__cxa_demangle,然后进行通配符匹配并决定是“删除”符号还是不理会它。
评论
objcopy
。