构建后从 C++ 动态库中删除一组符号(仅保留给定的一组)

问题描述 投票:0回答:1

我正在构建一个动态库(C++),它导出许多符号。

这些导出的符号(显然)与我的库的 API 匹配。 但是,我的库还导出了大量附加符号(我的公共标头中根本没有提到这些符号)。

为了保持我的库的二进制接口较小(防止名称冲突;不破坏符号空间;防止库的使用者不小心使用可能在下一个版本中消失的符号),我可以使导出使用版本脚本显式符号,就像这样(实际上版本脚本要复杂得多;无论如何,它涉及 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
     这样的工具会做一些不同的事情((GNU?)有一个 
    -N
     标志应该删除符号,但它似乎不起作用,即使对于普通的 C 库(没有 C++ 符号)损坏)
那么:有没有办法在构建后步骤中从库中删除符号(仅保留已知的集合)? 如果是这样,如何通过 C++ 符号修改和使用通配符来做到这一点?

c++ linux gcc shared-libraries strip
1个回答
0
投票
有没有办法在构建后步骤中从库中删除符号(仅保留已知的集合)?

是的。 (动态)符号名称位于

.dynstr

 部分,如果您覆盖那里的名称(例如,用 
_ZMyLib...
 覆盖 
_XMyLib
),动态链接器将无法解析这些符号。

迭代

.dynsym

(动态)符号表中的所有符号并不

如何通过 C++ 符号修改和使用通配符来做到这一点?

您必须对每个符号调用

__cxa_demangle,然后进行通配符匹配并决定是“zap”该符号还是保留它。

© www.soinside.com 2019 - 2024. All rights reserved.