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

post-build removal of a set of symbols (keeping only a given set) from C++ dynamic library

提问人:umläute 提问时间:10/24/2023 更新时间:10/26/2023 访问量:44

问:

我正在构建一个动态库(在 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++ 符号修改和使用通配符来做到这一点?

C++ Linux GCC 共享库

评论

0赞 G.M. 10/24/2023
它不处理名称 (de) mangling,但您可能想查看 objcopy

答:

0赞 Employed Russian 10/26/2023 #1

有没有办法在构建后步骤中从库中删除符号(仅保留已知集合)?

是的。(动态)符号名称驻留在该部分中,如果覆盖其中的名称(例如,覆盖 ),动态链接器将无法解析这些符号。.dynstr_ZMyLib..._XMyLib

遍历(动态)符号表中的所有符号并不.dynsym

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

您必须对每个符号调用__cxa_demangle,然后进行通配符匹配并决定是“删除”符号还是不理会它。