TL;DR: Use ldd -r libHello.so
to find unresolved symbols in your libHello.so
. Another option is to make your linker complain about theese symbols (with --no-undefined
for ld
). Or look for linking/loading errors later.
For example, you have:
// a.cpp
namespace X {
int someExternValue = 0;
}
// b.cpp
namespace x {
extern int someExternValue;
}
extern "C" { // for dlsym example
void setExternValue(int v)
{
x::someExternValue = v;
}
int getExternValue()
{
return x::someExternValue;
}
}
This will successfully build and link into .so
. Those undefined symbols are left to be resolved later "by someone else".
user@host:~$ ldd -r libHello.so
linux-vdso.so.1 (0x00007ffc99b15000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007f6bfe767000)
libm.so.6 => /usr/lib/libm.so.6 (0x00007f6bfe621000)
libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007f6bfe607000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f6bfe440000)
/usr/lib64/ld-linux-x86-64.so.2 (0x00007f6bfe9c0000)
undefined symbol: _ZN1x15someExternValueE (./libHello.so)
Of course, you'll get complains about that when linking some executable to libHello
:
// hello_main.cpp
#include <iostream>
extern "C" {
void setExternValue(int);
int getExternValue();
}
int main(int, char *[])
{
std::cout << getExternValue() << std::endl;
setExternValue(10);
std::cout << getExternValue() << std::endl;
return 0;
}
Oops:
/usr/bin/ld: libHello.so: undefined reference to ``x::someExternValue'
Mostly the same goes for dynamic loading:
// hello_dlsym.cpp
#include <iostream>
#include <dlfcn.h>
typedef void (*setValueFunc)(int);
typedef int (*getValueFunc)();
int main(int, char *[])
{
auto libHandle = dlopen("./libHello.so", RTLD_LAZY);
if (!libHandle) {
std::cerr << "dlopen failure: " << dlerror() << std::endl;
return EXIT_FAILURE;
}
getValueFunc getV = reinterpret_cast<getValueFunc>(dlsym(libHandle, "getExternValue"));
if (!getV) {
std::cerr << "failed to get getValueFunc: " << dlerror() << std::endl;
return EXIT_FAILURE;
}
setValueFunc setV = reinterpret_cast<setValueFunc>(dlsym(libHandle, "setExternValue"));
if (!setV) {
std::cerr << "failed to get setValueFunc: " << dlerror() << std::endl;
return EXIT_FAILURE;
}
std::cout << getV() << std::endl;
setV(10);
std::cout << getV() << std::endl;
dlclose(libHandle);
return EXIT_SUCCESS;
}
The same oops:
dlopen failure: ./libHello.so: undefined symbol: _ZN1x15someExternValueE
The worst thing is when libHello
is a plugin to some app and that app doesn't give any info why it couldn't load your plugin or you don't know where to look for logs.
BTW Unity editor logs are located at ~/.config/unity3d/Editor[-prev].log
on Linux and undefined symbol errors in your native plugins will be listed there.
All files for the example are added below.
Relevant blog post.