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

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

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

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

One solution I did come up with is to run the compiled library through nm -C -U to 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 nm to grep through 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?

58747 次浏览

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.

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:

  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.

Hope that helps.

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

UPDATE: a trivial way to create a.out against which to check:

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

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.

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

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:

> 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