使用与其他共享库链接的共享库

时间:2013-06-20 23:25:27

标签: c++ macos linker dylib undefined-symbol

我在OSX上编译了一个带有一些外部依赖的共享库( boost OpenGL ):

g++ -dynamiclib -undefined suppress -flat_namespace -o "libMY_LIB.dylib" ./windowbase.o -lGL -lGLU -lGLUT -lboost_system -lboost_thread

没有错误,file libMY_LIB.dylib会产生Mach-O 64-bit dynamically linked shared library x86_64otool -L libMY_LIB.dylib输出:

libPixelsGL.dylib (compatibility version 0.0.0, current version 0.0.0)
/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib (compatibility version 1.0.0, current version 1.0.0)
/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGLU.dylib (compatibility version 1.0.0, current version 1.0.0)
/System/Library/Frameworks/GLUT.framework/Versions/A/GLUT (compatibility version 1.0.0, current version 1.0.0)
libboost_system.dylib (compatibility version 0.0.0, current version 0.0.0)
libboost_thread.dylib (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 52.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 159.1.0)

现在我尝试使用libMY_LIB.dylib中的函数(并在lib中编译)链接MY_LIB.h的{​​{1}}可执行文件:

g++ -L"/path/to/MY_LIB" -o "Program" ./main.o -lMY_LIB

但它失败了,打印:

Undefined symbols for architecture x86_64:
"boost::system::system_category()", referenced from:
    __static_initialization_and_destruction_0(int, int)in main.o
    boost::mutex::mutex()in main.o
    boost::mutex::lock()    in main.o
    boost::mutex::unlock()    in main.o
"boost::system::generic_category()", referenced from:
    __static_initialization_and_destruction_0(int, int)in main.o
"boost::thread::detach()", referenced from:
    boost::thread::~thread()in main.o
ld: symbol(s) not found for architecture x86_64

一些解释和/或帮助?

谢谢!

修改

我尝试将没有-undefined suppress -flat_namespace标志的lib和可执行文件与它们链接起来,后者起作用。可以请任何人告诉我为什么?可能是 boost libs我用这些标志编译了吗?

再次感谢!

1 个答案:

答案 0 :(得分:5)

您遇到的最重要的问题是,您没有将应用程序与提供其使用的符号的库链接起来。

您的错误消息会调出main.o包含对boost::system::system_category()boost::system::generic_category()boost::thread::detach()的引用。因此,在将main.o链接到可执行二进制文件时,您需要链接到提供这些符号的库,在这种情况下,传递-lboost_system -lboost_thread


至于-undefined suppress -flat_namespace:这些选项具有将缺失符号的检测从构建时间移动到运行时的效果。通常,除非您有特殊需要,否则应避免使用这些标志。使用这些标志“工作”构建主可执行文件的原因是您已经要求链接器不要为丢失的符号生成错误。由于它不知道这些符号,因此无需确保提供它们的库在运行时加载到应用程序的地址空间。你很幸运,因为符号恰好由你libMY_LIB.dylib也链接到的图书馆提供。

为了便于说明,请考虑一个导出函数liba.dylib的简单测试库a

$ cat a.c
int a(void)
{
    return 1;
}
$ cc -dynamiclib -o liba.dylib a.c
$

一个使用此功能的简单应用程序:

$ cat main.c
#include <stdio.h>

extern int a(void);

int main(int argc, char **argv)
{
    fprintf(stderr, "a: %d\n", a());
    return 0;
}

现在让我们看看将这个库链接到我们的应用程序的三种方法。

1)根本没有指定库

$ cc -o main main.c 
Undefined symbols for architecture x86_64:
  "_a", referenced from:
      _main in main-JmKbTd.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

这是您最初报告在您的问题中看到的情况。

2)指定-undefined suppress -flat_namespace

$ cc -undefined suppress -flat_namespace -o main main.c 
$

成功创建了一个可执行文件,但是当我们运行二进制文件时:

$ ./main 
dyld: lazy symbol binding failed: Symbol not found: _a
  Referenced from: /tmp/./main
  Expected in: flat namespace

dyld: Symbol not found: _a
  Referenced from: /tmp/./main
  Expected in: flat namespace

Trace/BPT trap: 5

在这种情况下,运行时的加载器不知道需要加载liba.dylib才能找到函数a

$ otool -L main 
main:
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.0.0)
$ nm -m main | grep _a
                 (undefined) external _a
$ 

3)正确指定库

$ cc -L. -la -o main main.c 
$ ./main 
a: 1
$ 

您可以看到二进制文件main知道要加载liba.dylib,而liba.dylib知道a提供main使用的函数$ otool -L main main: liba.dylib (compatibility version 0.0.0, current version 0.0.0) /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.0.0) $ nm -m main | grep _a (undefined) external _a (from liba) $

-undefined suppress -flat_namespace

总之,我的建议是在构建库和二进制文件时完全停止传递{{1}},并确保每个组件链接到它使用的符号所需的库。