为什么在使用 clang 和 libc++ 时出现以下链接器错误:
$ clang++ -stdlib=libc++ po.cxx -lpoppler
/tmp/po-QqlXGY.o: In function `main':
po.cxx:(.text+0x33): undefined reference to `Dict::lookup(char*, Object*, std::__1::set<int, std::__1::less<int>, std::__1::allocator<int> >*)'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
地点:
$ nm -D /usr/lib/x86_64-linux-gnu/libpoppler.so | grep lookup | c++filt| grep \ Dict::lookup\(
00000000000c1870 T Dict::lookup(char*, Object*, std::set<int, std::less<int>, std::allocator<int> >*)
代码很简单:
#include <poppler/PDFDoc.h>
int main()
{
Dict *infoDict;
Object obj;
infoDict->lookup((char*)"key", &obj);
return 0;
}
根据您的错误,应该就像您尝试将 libc++ 与 stdlibc++ 链接一样, libc++ 和 stdlibc++ 是不同的,stdlibc++ 是 gcc 的 c++ 标准库,它不会互相兼容。
对于你的问题,就像你的 libpoppler.so 正在使用 stdlibc++, 但是在您的 clang 命令行中,您尝试使用 libc++ 作为标准库,它们在链接阶段具有不同的名称,请参阅本答案末尾的链接以了解详细原因。
所以,也许你的解决方案只是将编译命令更改为
clang++ -stdlib=libstdc++ po.cxx -lpoppler
请参阅此问题以详细了解为什么 std:__1::set 和 std::set。
为什么不能在 c++0x 模式下用 libc++ clang 链接这个 boost::program_options 示例?
因为
libpoppler.so
与 GNU stdlibc++ 链接。单个可执行文件的所有部分都必须链接到相同的标准 C 和相同的标准 C++ 库。
最简单的选择是使用默认的标准库。两者现在大部分都是 C++11 完整的。
或者,您可以针对
libpoppler.so
构建 libc++
的版本,但您必须为其指定不同的名称,以便动态链接器找到正确的名称。
在链接错误中,您可以看到
libpoppler.so
指的是 std::set
和 std::less
等,但您的对象想要引用 std::__1::set
和 std::__1::less
等。这是因为 GNU stdlibc++ 和 Clang libc++ 方法版本控制不同。
因为 libc++ 使用与 GNU C++ 标准库不同的命名空间。这个链接器错误是一件好事,因为对于某些类型来说,两个库类型的布局肯定会有所不同。
所以这意味着你的“poppler”库是针对 GNU C++ std 库构建的,它有一组名称 - 而编译器在程序翻译中使用 libc++ 中的声明来调用函数。因此,链接器在对象(例如 poppler 库)中查找具有 std 库声明的 libc++ 命名的符号,但它找不到它们,因为它们不是以相同的名称发出的 - 它们可能存在于 poppler 库中与 GNU 名称。
当然,您可能只关心如何解决这个问题:使用相同的标准库构建您的程序和 poppler 库。如果您无法构建 poppler 库,您将不得不等待他们推出针对 libc++ 构建的二进制文件。