库不能正常导出功能

时间:2016-09-09 07:58:10

标签: c++ c linux shared-libraries libtool

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

但是在Linux下有一个问题,当试图调用其中一个函数时,调用应用程序终止时找不到"符号"信息。令人惊讶的是,当我查看.so文件(使用午夜指挥官)时,我可以看到相关符号在那里,所以在我看来没有理由为什么它会失败!

这是库定义的示例。

标题:

#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

所以在我看来,没有理由在运行时找不到符号。任何想法可能是什么原因?

1 个答案:

答案 0 :(得分:1)

您的链接出现问题。符号是编译时但不是运行时?您是否使用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',这是未定义的,正如预期的那样。符号为'T',即文本部分和外部,也是预期的。运行该程序按预期方式工作。看看你的符号与nm的依赖关系,也许符号状态是错误的。

另一种可能性是extern C签名在库或main中是错误的。确保符号在nm输出中没有损坏

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

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