c++ - 使用与其他共享库链接的共享库

标签 c++ macos linker dylib undefined-symbol

我在 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_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)

现在我尝试将可执行文件链接到 libMY_LIB.dylib ,仅使用 MY_LIB.h 中的函数(并在库中编译):

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 的情况下链接库标志和带有它们的可执行文件,后者起作用了。请问有人可以告诉我为什么吗?我的库可能是用这些标志编译的boost吗?

再次感谢!

最佳答案

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

您的错误消息指出 main.o 包含对 boost::system::system_category()boost::system::generic_category( ) 和 boost::thread::detach() 。因此,当将 main.o 链接到可执行二进制文件时,您需要链接到提供这些符号的库,在本例中通过传递 -lboost_system -lboost_thread p>


至于-undefined suggest -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 suggest -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 提供了该函数main 使用的 a:

$ 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 suggest -flat_namespace ,并确保每个组件链接到其使用的符号的必要库.

关于c++ - 使用与其他共享库链接的共享库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17225464/

相关文章:

c++ - 比较 C++ 中的 int 和 bitset

c++ - 在没有 delete 运算符的情况下编译 C++

python - Tox 总是需要 30 秒才能运行

objective-c - 删除 NSTextView 上的一行文本

macos - 如何在 Mac OS X 或 iOS 中以编程方式找到路由器的 IP 地址?

c++ - 使用 Microsoft Visual Studio 2010 IDE 进行精确的库链接顺序控制

c - 如何快速搜索库中 undefined reference 。

c++ - stringstream operator<< 按位求反不能按预期工作

c++ - 如何 "invalidate"一个像STL迭代器的对象

c++ - 奇怪的构造函数