轻松检查共享库中未解析的符号?

Dav*_*dge 75 c++ linker shared-libraries

我正在编写一个相当大的C++共享对象库,并遇到了一个小问题,使调试变得很麻烦:

如果我在头文件中定义一个函数/方法,并忘记为它创建一个存根(在开发期间),因为我构建为共享对象库而不是可执行文件,编译时没有出现错误告诉我我有忘记实现这个功能.我发现错误的唯一方法是在运行时,最终链接到此库的应用程序会出现"未定义的符号"错误.

我正在寻找一种简单的方法来检查我是否在编译时拥有所需的所有符号,也许我可以添加到我的Makefile中.

我提出的一个解决方案是运行已编译的库nm -C -U以获取所有未定义引用的demangled列表.问题是,这也与在其他库,如glibc的,这当然会反对与此相伴库时,最终的应用程序放在一起链接的所有引用的列表中出现.有可能使用输出nmgrep通过我的所有头文件,看看是否有任何相应的名称...但这似乎是疯了.当然,这不是一个罕见的问题,有一个更好的解决方法吗?

R S*_*hko 88

查看链接器选项-z defs/ --no-undefined.创建共享对象时,如果存在未解析的符号,则会导致链接失败.

如果使用gcc调用链接器,则将使用编译器-Wl选项将选项传递给链接器:

gcc -shared ... -Wl,-z,defs
Run Code Online (Sandbox Code Playgroud)

例如,请考虑以下文件:

#include <stdio.h>

void forgot_to_define(FILE *fp);

void doit(const char *filename)
{
    FILE *fp = fopen(filename, "r");
    if (fp != NULL)
    {
        forgot_to_define(fp);
        fclose(fp);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,如果您将其构建为共享对象,它将成功:

> gcc -shared -fPIC -o libsilly.so silly.c && echo succeeded || echo failed
succeeded
Run Code Online (Sandbox Code Playgroud)

但是如果你添加-z defs,链接将失败,并告诉你你缺少的符号:

> gcc -shared -fPIC -o libsilly.so silly.c -Wl,-z,defs && echo succeeded || echo failed
/tmp/cccIwwbn.o: In function `doit':
silly.c:(.text+0x2c): undefined reference to `forgot_to_define'
collect2: ld returned 1 exit status
failed
Run Code Online (Sandbox Code Playgroud)

  • +1这个答案可以帮助那些来自Windows背景的人,在编译期间必须解析*DLL*外部符号.方法去寻找漂亮的代码片段! (3认同)

Emp*_*ian 14

在Linux上(您似乎正在使用)ldd -r a.out应该为您提供您正在寻找的答案.

更新:创建一个简单的方法a.out来检查:

 echo "int main() { return 0; }" | g++ -xc++ - ./libMySharedLib.so
 ldd -r ./a.out
Run Code Online (Sandbox Code Playgroud)

  • 这与nm -C -U几乎完全相同,我在原帖中提到过.问题是没有'a.out'应用程序可以说,它是一个共享库,所以ldd -r mylibrary.so提供了一大堆输出,因为它使用来自各种其他动态库的符号..我特别感兴趣缺少在*my*头文件中定义的符号,而不是外部库. (3认同)
  • 这个应该被接受,问题是检查未定义符号的简单方法是什么,而不是如何避免未定义符号 (2认同)

Ste*_*ini 8

那个测试套件怎么样?您可以创建链接到所需符号的模拟可执行文件.如果链接失败,则表示您的库接口不完整.