我正在构建一个动态库(用C编写),它可以导出许多符号。
这些导出的符号(很明显)与我的库的API相匹配。2然而,我的库还导出了过多的附加符号(在我的公共头中根本没有提到)。
为了使我的库的二进制接口保持较小(防止名称冲击;不破坏符号空间;防止库的使用者 * 意外地 * 使用可能在下一个版本中消失的符号),我可以使用版本脚本显式地导出符号,如下所示(实际上版本脚本要复杂得多;在任何情况下,它都涉及到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
(或其他一些显式的构建后步骤)期间,不必要的符号将被剥离。
不幸的是,我不知道如何实现这一点。
- 版本脚本是链接器的一个功能
- 像
strip
这样的工具做了一些不同的事情(有一个-N
标记到(GNU?)strip,它应该删除一个符号,但它似乎不工作,即使是一个普通的C库(没有C++符号混乱)
于是:有没有一种方法可以在编译后的步骤中从库中去掉符号(只保留一个已知的集合)?2如果有,如何通过C++符号的修饰和使用通配符来做到这一点?
1条答案
按热度按时间xkrw2x1b1#
有没有一种方法可以在构建后的步骤中从库中删除符号(只保留一个已知的集合)?
是的。(动态)符号名称位于
.dynstr
部分,如果您覆盖那里的名称(例如,用_XMyLib
覆盖_ZMyLib...
),动态链接器将不会解析这些符号。迭代
.dynsym
(动态)符号表中的所有符号不是hard。如何使用C++符号处理和使用通配符?
您必须在每个符号上调用__cxa_demangle,然后进行字符串匹配,并决定是“zap”该符号还是不处理它。