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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1617286/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 20:37:39  来源:igfitidea点击:

Easy check for unresolved symbols in shared libraries?

c++linkershared-libraries

提问by David Claridge

I am writing a fairly large C++ shared-object library, and have run into a small issue that makes debugging a pain:

我正在编写一个相当大的 C++ 共享对象库,并且遇到了一个让调试变得痛苦的小问题:

If I define a function/method in a header file, and forget to create a stub for it (during development), since I am building as a shared object library rather than an executable, no errors appear at compile-time telling me I have forgotten to implement that function. The only way I find out something is wrong is at runtime, when eventually an application linking against this library falls over with an 'undefined symbol' error.

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

I am looking for an easy way to check if I have all the symbols I need at compile time, perhaps something I can add to my Makefile.

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

One solution I did come up with is to run the compiled library through nm -C -Uto get a demangled list of all undefined references. The problem is this also comes up with the list of all references that are in other libraries, such as GLibC, which of course will be linked against along with this library when the final application is put together. It would be possible to use the output of nmto grepthrough all my header files and see if any of the names corresponding.. but this seems insane. Surely this is not an uncommon issue and there is a better way of solving it?

我想出的一个解决方案是运行编译后的库nm -C -U以获取所有未定义引用的经过整理的列表。问题在于,这也带来了其他库(例如 GLibC)中所有引用的列表,当最终应用程序组合在一起时,这些库当然会与该库一起链接。这将有可能使用的输出nm,以grep通过所有我的头文件,看看是否有任何名称的对应..但这似乎疯了。这当然不是一个罕见的问题,有更好的解决方法吗?

回答by R Samuel Klatchko

Check out the linker option -z defs/ --no-undefined. When creating a shared object, it will cause the link to fail if there are unresolved symbols.

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

If you are using gcc to invoke the linker, you'll use the compiler -Wloption to pass the option to the linker:

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

gcc -shared ... -Wl,-z,defs

As an example, consider the following file:

例如,请考虑以下文件:

#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);
    }
}

Now, if you build that into a shared object, it will succeed:

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

> gcc -shared -fPIC -o libsilly.so silly.c && echo succeeded || echo failed
succeeded

But if you add -z defs, the link will fail and tell you about your missing symbol:

但是如果您添加-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

回答by Employed Russian

On Linux (which you appear to be using) ldd -r a.outshould give you exactly the answer you are looking for.

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

UPDATE: a trivial way to create a.outagainst which to check:

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

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

回答by Stefano Borini

What about a testsuite ? You create mock executables that link to the symbols you need. If the linking fails, it means that your library interface is incomplete.

测试套件怎么样?您创建链接到所需符号的模拟可执行文件。如果链接失败,说明你的库接口不完整。

回答by Diego Sevilla

I had the same problem once. I was developing a component model in C++, and, of course, components should load at runtime dynamically. Three solutions come to mind, that were the ones I applied:

我曾经遇到过同样的问题。我正在用 C++ 开发一个组件模型,当然,组件应该在运行时动态加载。我想到了三种解决方案,那就是我应用的:

  1. Take some time to define a build system that is able to compile statically. You'll lose some time engineering it, but it will save you much time catching these annoying runtime errors.
  2. Group your functions in well-known and well-understood sections, so that you can group of functions/stubs to be sure that each corresponding function has its stub. If you take the time on documenting it well, you can write perhaps a script that checks the definitions (via, for example, its doxygen comments) and check the corresponding .cpp file for it.
  3. Do several test executables that load the same set of libraries and specify the RTLD_NOW flag to dlopen (if you're under *NIX). They will signal the missing symbols.
  1. 花一些时间来定义一个能够静态编译的构建系统。您会浪费一些时间来设计它,但它会为您节省很多时间来捕捉这些烦人的运行时错误。
  2. 将您的函数分组在众所周知且易于理解的部分,以便您可以对函数/存根进行分组,以确保每个相应的函数都有其存根。如果您花时间很好地记录它,您可以编写一个脚本来检查定义(例如,通过它的 doxygen 注释)并检查相应的 .cpp 文件。
  3. 执行多个加载相同库集的测试可执行文件,并将 RTLD_NOW 标志指定为 dlopen(如果您在 *NIX 下)。他们将发出信号丢失的符号。

Hope that helps.

希望有帮助。