【问题标题】:ld undefined reference, despite library found and symbols exportedld 未定义的引用,尽管找到了库并导出了符号
【发布时间】:2017-02-13 10:39:04
【问题描述】:

现在已经断断续续地与它战斗了 48 小时;尝试将动态库与其依赖项链接时,我仍然遇到未定义的引用错误 - 尽管所有导出都存在,并且已成功找到该库。

场景:

  • 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 也没有导致任何变化。

无论使用 clang 还是 gcc,结果都是一样的。

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

【问题讨论】:

  • missing -soname 是否与您的问题有关?
  • @AdrianColomitchi 尝试为两者添加合适的 -soname 参数,没有区别
  • @Leon,遗憾的是 -DC 的输出与 -gC 的输出相同
  • 我现在正在工作,但今晚回来时会将其删除。毫无疑问,我可能会在开始时找到解决方案......!

标签: c++ c linux gcc dynamic-linking


【解决方案1】:

所以,我剥离了合并的最后部分,并发现了问题。

我的导入/导出是以此为模型的: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(可见性隐藏)导致问题;我将其替换为空白定义,一切正常。是的,我确实也有 clang 的等价物,这就是为什么它也以同样的方式失败。

我从中得出的结论是,C 代码只会将这些可能成为符号的符号视为隐藏,因此无论多么努力,无论它们实际存在多少,都无法导入它们!

【讨论】:

    【解决方案2】:

    您应该将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
    

    内存.cpp

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

    内存.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;
    }
    

    生成文件:

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

    和构建日志:

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

    请参阅更多详细信息 Using C++ library in C codewiki How to mix C and C++

    【讨论】:

    • 是的,我怀疑有些更复杂的东西出了问题。这段代码(以及我还没有得到的其他库)已经完全构建在 Windows 的 msvc2015 中,如果我禁用内存调试(因此永远不会使用或导出 MEM_priv* 函数),它确实可以工作。我会把它精简到最低限度,看看今晚晚些时候我会发现什么。
    猜你喜欢
    • 2022-09-27
    • 2012-12-06
    • 1970-01-01
    • 1970-01-01
    • 2016-06-01
    • 2014-05-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-13
    相关资源
    最近更新 更多