库未正确导出功能

Posted

技术标签:

【中文标题】库未正确导出功能【英文标题】:Library not exporting function properly 【发布时间】:2016-09-09 07:58:09 【问题描述】:

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

但在 Linux 下存在一个问题,当试图调用其中一个函数时,调用应用程序以“未找到符号”消息终止。令人惊讶的是,当我查看 .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

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

【问题讨论】:

你的函数不是装饰了吗?什么给了你readelf -Ws yourlib.so,或nm -D yourlib.so 【参考方案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

现在是一个简单的 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;

编译并检查符号依赖关系

/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 看看你的符号依赖关系,也许符号状态是错误的。

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

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

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

【讨论】:

nm 返回“0000000000003f80 T MY_set_connection”,所以函数应该可以吧?加载是通过 dl_open 动态完成的。 是的,这对图书馆来说是正确的。在您的可执行文件上执行 nm 也是如此。还可以使用 ldd 确保您获得正确版本的库

以上是关于库未正确导出功能的主要内容,如果未能解决你的问题,请参考以下文章

部署原型工件时,Nexus Maven 原型存储库未更新

Java POI怎样判断导出的Excel数据是不是正确地保存到本地。考虑网络中断,客户不正确操作等因素。

CocoaLibSpotify - 库未加载

在ssh框架中使用poi正确导出具有比较高级固定格式的excel 整体过程,查询导出前后台下载

PLSQL导入导出表的正确步骤

这种导出文件的方法是不是正确?