I am writing a fairly large C++ shared-object library, and have run into a small issue that makes debugging a pain:
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.
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?
At link time, a static library can have unresolved symbols in it, as long as you don't need the unresolved symbols, and you don't need any symbol that is in a .o file that contains an unresolved symbol.
The unresolved external symbol is a linker error that indicates it cannot find the symbol or its reference during the linking process.
An undefined symbol is a symbol that the library uses but was not defined in any of the object files that went into creating the library. Usually the symbol is defined in another library which also needs to be linked in to your application.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With