库不能正确导出功能

Library not exporting function properly

本文关键字:功能 不能      更新时间:2023-10-16

我有一个Windows和Linux的共享库(.dll和.so)。除了用于平台之间差异的一些定义外,代码完全相同。Windows-DLL工作正常,所有的符号都被导出,可以被调用者使用。

但是在Linux下有一个问题,当尝试调用其中一个函数时,调用应用程序以"symbol not found"消息终止。令人惊讶的是,当我查看。so文件(使用Midnight Commander)时,我可以看到相关的符号在那里,所以在我看来,它没有理由失败!

这是一个标准库定义的示例。

标题:

#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

和实现:

MY_API unsigned char MY_set_connection(const char *address)
{
   // some code here
}

所以头文件和c文件中的函数定义是相同的,库是用

构建的
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

所以在我看来,应该没有理由在运行时找不到符号。知道原因是什么吗?

你的链接有问题。在编译时而不是运行时找到了符号?您是否使用dl_open来运行时链接库?

我把这个简单的例子放在一起调试。

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

然后编译并查看符号

/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

现在是一个简单的主

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

编译并检查符号依赖

/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

MY_set_connection是'U',在main中是未定义的。符号是"T",这是文本部分和外部,也是预期的。运行程序按预期工作。看看你的符号依赖于nm,也许符号状态是错误的。

另一种可能是外部C签名在库或主程序中是错误的。确保符号在nm输出

中没有被打乱。

查看ldd输出,以确保在运行时链接到正确的库。运行时链接到错误版本的共享库将会给出未定义的符号。

ldd ./a.out
    libtest_library.so => /tmp/libtest_library.so (0x00002b5df4ca7000)