ld未定义的参考,尽管已找到库并已导出符号

ld未定义的参考,尽管已找到库并已导出符号

问题描述:

现在已经连续打了48个小时,尝试将动态库链接到其依赖项时,仍然收到未定义的引用错误 - 尽管所有导出都存在,并且库已成功找到。ld未定义的参考,尽管已找到库并已导出符号

场景:

  • libmemory(C++) - 出口与extern "C"
  • libstring(C)函数 - 出口的功能,从libmemory

libmemory进口成功生成:

$ g++ -shared -fPIC -o ./builds/libmemory.so ...$(OBJECTS)... 

libstring编译成功,但未能链接:

$ gcc -shared -fPIC -o ./builds/libstring.so ...$(OBJECTS)... -L./builds -lmemory 
./temp/libstring/string.o: In function `STR_duplicate': 
string.c:(.text+0x1cb): undefined reference to `MEM_priv_alloc' 
./temp/libstring/string.o: In function `STR_duplicate_replace': 
string.c:(.text+0x2a0): undefined reference to `MEM_priv_free' 
string.c:(.text+0x2bf): undefined reference to `MEM_priv_alloc' 
/usr/bin/ld: ./builds/libstring.so: hidden symbol `MEM_priv_free' isn't defined 
/usr/bin/ld: final link failed: Bad value 
collect2: error: ld returned 1 exit status 

验证libmemory出口的符号和库本身是通过使用-v到GCC发现:

... 
attempt to open ./builds/libmemory.so succeeded 
-lmemory (./builds/libmemory.so) 
... 

$ nm -gC ./builds/libmemory.so | grep MEM_ 
0000000000009178 T MEM_exit 
0000000000009343 T MEM_init 
00000000000093e9 T MEM_print_leaks 
00000000000095be T MEM_priv_alloc 
000000000000971d T MEM_priv_free 
00000000000099c1 T MEM_priv_realloc 
0000000000009d26 T MEM_set_callback_leak 
0000000000009d3f T MEM_set_callback_noleak 

$ objdump -T ./builds/libmemory.so | grep MEM_ 
0000000000009d3f g DF .text 0000000000000019 Base  MEM_set_callback_noleak 
00000000000093e9 g DF .text 00000000000001d5 Base  MEM_print_leaks 
0000000000009d26 g DF .text 0000000000000019 Base  MEM_set_callback_leak 
00000000000099c1 g DF .text 0000000000000365 Base  MEM_priv_realloc 
0000000000009343 g DF .text 00000000000000a6 Base  MEM_init 
00000000000095be g DF .text 000000000000015f Base  MEM_priv_alloc 
000000000000971d g DF .text 00000000000002a4 Base  MEM_priv_free 
0000000000009178 g DF .text 00000000000000a7 Base  MEM_exit 

$ readelf -Ws ./builds/libmemory.so | grep MEM_ 
    49: 0000000000009d3f 25 FUNC GLOBAL DEFAULT 11 MEM_set_callback_noleak 
    95: 00000000000093e9 469 FUNC GLOBAL DEFAULT 11 MEM_print_leaks 
    99: 0000000000009d26 25 FUNC GLOBAL DEFAULT 11 MEM_set_callback_leak 
    118: 00000000000099c1 869 FUNC GLOBAL DEFAULT 11 MEM_priv_realloc 
    126: 0000000000009343 166 FUNC GLOBAL DEFAULT 11 MEM_init 
    145: 00000000000095be 351 FUNC GLOBAL DEFAULT 11 MEM_priv_alloc 
    192: 000000000000971d 676 FUNC GLOBAL DEFAULT 11 MEM_priv_free 
    272: 0000000000009178 167 FUNC GLOBAL DEFAULT 11 MEM_exit 
    103: 0000000000009343 166 FUNC GLOBAL DEFAULT 11 MEM_init 
    108: 0000000000009178 167 FUNC GLOBAL DEFAULT 11 MEM_exit 
    148: 0000000000009d3f 25 FUNC GLOBAL DEFAULT 11 MEM_set_callback_noleak 
    202: 00000000000095be 351 FUNC GLOBAL DEFAULT 11 MEM_priv_alloc 
    267: 000000000000971d 676 FUNC GLOBAL DEFAULT 11 MEM_priv_free 
    342: 0000000000009d26 25 FUNC GLOBAL DEFAULT 11 MEM_set_callback_leak 
    346: 00000000000099c1 869 FUNC GLOBAL DEFAULT 11 MEM_priv_realloc 
    366: 00000000000093e9 469 FUNC GLOBAL DEFAULT 11 MEM_print_leaks 

有什么可怕的简单的我失踪?所有其他相关的问题都有简单的答案,例如链接库的顺序和使用的路径 - 但我已经验证它们已经到位并按预期工作。

-fvisibility修修补补导致没有任何变化。

相同的结果是否存在使用铛或GCC。

Linux 3.16.0-38-generic gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.3)

+0

[缺少'-soname'](http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html)与您的问题有什么关系? –

+0

@AdrianColomitchi尝试在两者中添加一个合适的-soname参数,没有区别 – ZXcvbnM

+0

@Leon,-DC的输出与-gC的输出很相似 – ZXcvbnM

所以,我剥出合并的最后部分的详细信息,以及发现的问题。

我的导入/导出为蓝本关闭的这一点:https://gcc.gnu.org/wiki/Visibility

我相当于实施最终看起来像这样:

#  if GCC_IS_V4_OR_LATER 
#    define DLLEXPORT  __attribute__((visibility("default"))) 
#    define DLLIMPORT  __attribute__((visibility("hidden"))) 
#  else 
#    define DLLEXPORT 
#    define DLLIMPORT 
#  endif 

的dllimport的(可见性隐藏)引起的问题;我用一个空白的定义替换它,它都可以。是的,我也有类似的铿锵声,这也是为什么它也以相同的方式失败的原因。

我从这里得到的结论是,C代码只将这些可能的符号看作是隐藏的,因此无论尝试多么困难,无论它们实际存在多少,都不能导入它们!

你应该标记MEM_priv_alloc()功能extern "C"或包裹函数体为extern "C" { /* function implementation */ }(已经做了,我可以从描述看)。在头部的__cplusplusextern "C" 并运用组合

#ifdef __cplusplus 
    #define EXTERNC extern "C" 
#else 
    #define EXTERNC 
#endif 

EXTERNC int MEM_priv_alloc (void); 

也请仔细检查MEM_priv_alloc原型是如何完成的。例如,MEM_priv_alloc应该inline(不幸的是我不知道这个物理学中,但是inline例如失败对我来说)


下面是简化的例子,对我的作品:

文件:

$ ls 
main.c Makefile mem.cpp mem.h strings.c strings.h 

mem.cpp

#include <stdio.h> 
#include "mem.h" 
extern "C" int MEM_priv_alloc (void) 
{ 
    return 0; 
} 

mem.h

#ifdef __cplusplus 
    #define EXTERNC extern "C" 
#else 
    #define EXTERNC 
#endif 
EXTERNC int MEM_priv_alloc (void); 

strings.c:

#include <stdio.h> 
#include "mem.h" 
int STR_duplicate_replace (void) 
{ 
    MEM_priv_alloc(); 
} 

字符串。H:

int STR_duplicate_replace (void); 

的main.c

#include <stdio.h> 
#include "string.h" 
int main (void) 
{ 
    STR_duplicate_replace(); 
    return 0; 
} 

的Makefile:

prog: libmemory.so libstrings.so 
     gcc -o [email protected] -L. -lmemory -lstrings main.c 

libmemory.so: mem.cpp 
     g++ -shared -fPIC -o [email protected] $^ 

libstrings.so: strings.c 
     gcc -shared -fPIC -o [email protected] $^ 

,并生成日志:

g++ -shared -fPIC -o libmemory.so mem.cpp 
gcc -shared -fPIC -o libstrings.so strings.c 
gcc -o prog -L. -lmemory -lstrings main.c 

请一个LSO看到 Using C++ library in C codewiki How to mix C and C++

+0

是的,我怀疑更复杂的事情是错误的。这个代码(以及其他我尚未得到的库)已经在msvc2015 for Windows中完全构建,并且如果我禁用了我的内存调试(因此MEM_priv *函数从未被使用或导出),它也可以工作。我会把它分解成最小的,看看我今晚晚些时候会发现什么。 – ZXcvbnM