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

Eno*_*ach 2 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
Run Code Online (Sandbox Code Playgroud)

没有错误,file libMY_LIB.dylib结果Mach-O 64-bit dynamically linked shared library x86_64和otool -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)
Run Code Online (Sandbox Code Playgroud)

现在我尝试链接一个可执行文件libMY_LIB.dylib,只使用函数MY_LIB.h(并在lib中编译):

g++ -L"/path/to/MY_LIB" -o "Program" ./main.o -lMY_LIB
Run Code Online (Sandbox Code Playgroud)

但它失败了,打印:

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
Run Code Online (Sandbox Code Playgroud)

一些解释和/或帮助?

谢谢!

编辑

我试图链接lib没有-undefined suppress -flat_namespace标志和可执行文件与他们,后者工作.可以请任何人告诉我为什么?可以说,它是推动我已经用这些标志编译库?

再次感谢!

bda*_*ash 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
$
Run Code Online (Sandbox Code Playgroud)

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

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

extern int a(void);

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

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

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)
Run Code Online (Sandbox Code Playgroud)

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

2)指定 -undefined suppress -flat_namespace

$ cc -undefined suppress -flat_namespace -o main main.c 
$
Run Code Online (Sandbox Code Playgroud)

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

$ ./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
Run Code Online (Sandbox Code Playgroud)

在这种情况下,运行时的加载器不知道需要加载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
$ 
Run Code Online (Sandbox Code Playgroud)

3)正确指定库

$ cc -L. -la -o main main.c 
$ ./main 
a: 1
$ 
Run Code Online (Sandbox Code Playgroud)

你可以看到,二进制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)
$ 
Run Code Online (Sandbox Code Playgroud)

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