I have a shared library (.dll and .so) for Windows and Linux. Except some defines used for the differences between the platforms, the code is exactly the same. The Windows-DLL works properly, all symbols are exported and can be used by the caller.
But under Linux there is a problem, when trying to call one of the functions, the calling application terminates with a "symbol not found" message. Amazingly when I have a look into the .so-file (using Midnight Commander) I can see the related symbol is there, so in my opinion there is no reason why it should fail!
This is an example how the library definitions look like.
The Header:
#ifdef ENV_LINUX
#ifdef MY_EXPORTS
#define MY_API __attribute ((visibility ("default")))
#else
#define MY_API
#endif
#else
#ifdef MY_EXPORTS
#define MY_API __declspec(dllexport)
#else
#define MY_API __declspec(dllimport)
#endif
#endif
#ifdef __cplusplus
extern "C"
{
#endif
MY_API unsigned char MY_set_connection(const char *address);
#ifdef __cplusplus
};
#endif // __cplusplus
And the implementation:
MY_API unsigned char MY_set_connection(const char *address)
{
// some code here
}
So the function definitions in header and C-file are the same and the library is build with
CCOMPILER=libtool --mode=compile g++ -Wall -Wno-unused -fPIC -shared -fvisibility=hidden $(DBGFLAGS) -DMY_EXPORTS -D_REENTRANT -DENV_LINUX -I. -I.. $(CFLAGS) $(LFLAGS)
LINK=libtool --mode=link g++ -rpath /usr/lib
So in my opinion there should be no reason why the symbol can't be found during runtime. Any ideas what the reason could be?
Something is going wrong in your link. The symbol is found a compile time but not runtime? Are you using dl_open
to runtime link the library?
I put together this simple example to debug.
#include <iostream>
#ifdef ENV_LINUX
#ifdef MY_EXPORTS
#define MY_API __attribute ((visibility ("default")))
#else
#define MY_API
#endif
#else
#ifdef MY_EXPORTS
#define MY_API __declspec(dllexport)
#else
#define MY_API __declspec(dllimport)
#endif
#endif
#ifdef __cplusplus
extern "C"
{
#endif
MY_API unsigned char MY_set_connection(const char *address);
#ifdef __cplusplus
};
#endif // __cplusplus
unsigned char MY_set_connection(const char* address)
{
std::cout << "found it" << std::endl;
return 0;
}
Then compile and view symbols
/tmp$ g++ -fPIC -g -std=c++11 -shared -fvisibility=hidden -DMY_EXPORTS -D_REENTRANT -DENV_LINUX -o libtest_library.so lib.cpp
/tmp$ nm -D libtest_library.so | grep MY_set_connection
00000000000007c5 T MY_set_connection
Now a simple main
#ifdef __cplusplus
extern "C"
{
#endif
unsigned char MY_set_connection(const char *address);
#ifdef __cplusplus
};
#endif // __cplusplus
int main(int argc, char* argv[])
{
unsigned char rc = MY_set_connection("test");
return 0;
}
Compile and check symbol dependency
/tmp$ g++ -g -std=c++11 junk.cpp -DENV_LINUX -L . -l test_library
/tmp$ g++ -g junk.cpp -DENV_LINUX -L . -l test_library
/tmp$ nm a.out | grep MY_
U MY_set_connection
So MY_set_connection is 'U' ,which is undefined, in main as expected. The symbol is 'T', which is Text section and external, also expected. Running the program works as expected. Have a look at your symbol dependencies with nm, perhaps the symbol status is wrong.
Another possibility would the be extern C signature is wrong in the library or the main. Make sure the symbol is not mangled in either nm output
Have a look at the ldd output to make sure your are linking against the right library at runtime. Runtime linking against the wrong version of a shared library will give undefined symbols.
ldd ./a.out
libtest_library.so => /tmp/libtest_library.so (0x00002b5df4ca7000)