2

我已经在 OSX 上编译了一个具有一些外部依赖项(boostOpenGL)的共享库:

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,仅使用MY_LIB.h(并在 lib 中编译)中的函数:

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和可执行文件与它们链接起来,后者起作用了。谁能告诉我为什么?可能是我用这些标志编译的提升库吗?

再次感谢!

4

1 回答 1

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在构建库和二进制文件时完全停止传递,并确保每个组件都链接到它使用的符号所需的库。

于 2013-06-21T09:44:42.953 回答