3

这是我无法正确链接的这个相当微不足道的应用程序的设置。基本上是一个源文件main.cpp、一个包含静态库的目录libbreakpad_client.a以及breakpad.

$ ls .
main.cpp libs breakpad
$ ls libs
libbreakpad_client.a

这是从Google Breakpad 文档main.cpp逐字获取的源代码。

#include "client/linux/handler/exception_handler.h"

void crash()
{
  volatile int* a = (int*)(NULL);
  *a = 1;
}

static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context, bool succeeded)
{
  printf("Dump path: %s\n", descriptor.path());
  return succeeded;
}

int main()
{
    google_breakpad::MinidumpDescriptor descriptor("/tmp");
    google_breakpad::ExceptionHandler eh(descriptor, 0, dumpCallback, 0, true, -1);
    crash();
    return 0;
}

但是当我尝试编译它时,链接器抱怨它找不到ExceptionHandler构造函数和析构函数。

$ g++ -Ibreakpad/src -lbreakpad_client -Llibs -o main main.cpp
/tmp/ccDDGnQk.o: In function `main':
main.cpp:(.text+0xed): undefined reference to `google_breakpad::ExceptionHandler::ExceptionHandler(google_breakpad::MinidumpDescriptor const&, bool (*)(void*), bool (*)(google_breakpad::MinidumpDescriptor const&, void*, bool), void*, bool, int)'
main.cpp:(.text+0x106): undefined reference to `google_breakpad::ExceptionHandler::~ExceptionHandler()'
collect2: error: ld returned 1 exit status

但是,如果我们查看 中的符号libbreakpad_client.a我们会发现函数完全按照预期存在

$ nm -an libs/libbreakpad_client.a | c++filt | grep "ExceptionHandler("
000000000000076c T google_breakpad::ExceptionHandler::ExceptionHandler(google_breakpad::MinidumpDescriptor const&, bool (*)(void*), bool (*)(google_breakpad::MinidumpDescriptor const&, void*, bool), void*, bool, int)
000000000000076c T google_breakpad::ExceptionHandler::ExceptionHandler(google_breakpad::MinidumpDescriptor const&, bool (*)(void*), bool (*)(google_breakpad::MinidumpDescriptor const&, void*, bool), void*, bool, int)
0000000000000972 T google_breakpad::ExceptionHandler::~ExceptionHandler()
0000000000000972 T google_breakpad::ExceptionHandler::~ExceptionHandler()

那么为什么链接器抱怨这些是一个undefined reference

4

2 回答 2

7

编译器的标志顺序很重要。您需要将-l标志放在源文件名之后:

$ g++ -Ibreakpad/src -Llibs -o main main.cpp -lbreakpad_client

GCC 文档

在命令中编写此选项的位置有所不同;链接器按照指定的顺序搜索和处理库和目标文件。因此,在foo.o -lz bar.o文件z之后foo.o但在bar.o. 如果bar.o引用 中的函数z,则可能不会加载这些函数。

于 2013-09-25T18:34:29.997 回答
4

链接线的顺序很重要!库仅在参数列表中出现时才被搜索一次。如果此时没有未解析的符号,它们将不会发生任何其他事情。将您的命令更改为

g++ -Ibreakpad/src  -Llibs -o main main.cpp -lbreakpad_client
于 2013-09-25T18:37:06.570 回答