简体   繁体   English

c ++对类成员函数的未定义引用

[英]c++ undefined reference to a class member function

I encountered the following linking issues when trying to use librbd.我在尝试使用 librbd 时遇到了以下链接问题。

The following is my code snippet.以下是我的代码片段。

  • main.cc主文件
#include <iostream>
#include <rados/librados.hpp>
#include <rbd/librbd.hpp>

int main(){
    // Initialize and open an rbd image
    std::string pool = "xxx";
    std::string image_name = "xxxx";
    int r;
    librados::Rados cluster;
    librados::IoCtx io_ctx;
    librbd::Image image;
    librbd::RBD rbd;
    r = cluster.init("cinder-ctest");
    r = cluster.connect();
    r = cluster.ioctx_create(pool.c_str(), io_ctx);
    r = rbd.open_read_only(io_ctx, image, image_name.c_str(), NULL);

    std::string id;
    image.get_id(&id);   // <- Where the problem occurs
    std::cerr << id << std::endl;
    return 0;
}

An error occurred when I compiled using the following command我使用以下命令编译时发生错误

$ g++ main.cc -o info -lrbd -lrados 
/tmp/ccOpSFrv.o: In function `main':
main.cc:(.text+0x12b): undefined reference to `librbd::Image::get_id(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*)'
collect2: error: ld returned 1 exit status

but I use nm to see that get_id exists:但我使用 nm 来查看 get_id 存在:

$ nm -D /usr/lib64/librbd.so | grep get_id
0000000000083d00 T rbd_get_id
000000000008de10 T _ZN6librbd5Image6get_idEPSs
                 U _ZN8librados7v14_2_05IoCtx6get_idEv

and it is globally visible:它是全球可见的:

$ readelf -s /usr/lib64/librbd.so | grep get_id
   498: 0000000000083d00    70 FUNC    GLOBAL DEFAULT   11 rbd_get_id
   559: 000000000008de10    54 FUNC    GLOBAL DEFAULT   11 _ZN6librbd5Image6get_idEP

why do I get an error when compiling: undefined reference to librbd::Image::get_id .为什么在编译时出现错误:未定义引用librbd::Image::get_id It clearly exists, which makes me wonder.它显然存在,这让我感到奇怪。

Some background: C++11 changed the std::string interface slightly by adding noexcept specifiers to a few member functions, but it turns out that slight change meant that libstdc++ had to re-write their std::string implementation in a non-ABI-compatible way.一些背景:C ++ 11改变了std::string ,加入稍接口noexcept符的几个成员函数,但事实证明,细微的变化意味着的libstdc ++不得不重新编写他们std::string实现在非ABI 兼容方式。 For backwards compatibility, they retained the old version and put the new one in an inline namespace so it's named std::__cxx11::basic_string as far as the linker is concerned.为了向后兼容,他们保留了旧版本并将新版本放在一个内联命名空间中,因此就链接器而言,它被命名为std::__cxx11::basic_string See this page for more info.有关更多信息,请参阅此页面

That's where you're running into trouble.这就是你遇到麻烦的地方。 _ZN6librbd5Image6get_idEPSs demangles to _ZN6librbd5Image6get_idEPSs

librbd::Image::get_id(
    std::basic_string<
        char,
        std::char_traits<char>,
        std::allocator<char>
    >*
)

That function accepts the old version of std::string , but you're passing it a pointer to the new version of std::string .该函数接受旧版本的std::string ,但您将指针传递给新版本的std::string Presumably the version of librbd you have was either built with an old version of GCC, or was purposely built against the old ABI.据推测,您拥有的 librbd 版本要么是用旧版本的 GCC 构建的,要么是专门针对旧 ABI 构建的。

You have a few options to work around this:您有几个选项可以解决此问题:

  1. Find a version of librbd that was built for libstdc++'s new ABI.查找为 libstdc++ 的新 ABI 构建的 librbd 版本。
    • If the version you're using is from your distro's package manager, you may need to look elsewhere (like Conan or vcpkg or something).如果您使用的版本来自发行版的包管理器,您可能需要查看其他地方(例如 Conan 或 vcpkg 或其他东西)。
  2. Build librbd yourself against the new ABI.自己针对新的 ABI 构建 librbd。
    • I'm not familiar with that library, so I don't know how hard this would be.我不熟悉那个图书馆,所以我不知道这会有多难。 It seems that on some distros their toolchain prevents it .似乎在某些发行版上,他们的工具链阻止了它
  3. Build your application against the old ABI.针对旧的 ABI 构建您的应用程序。
    • As the page I linked above says, you can define the _GLIBCXX_USE_CXX11_ABI preprocessor macro to 0 to tell libstdc++ to use the old implementation of std::string .正如我上面链接的页面所说,您可以将_GLIBCXX_USE_CXX11_ABI预处理器宏定义为0以告诉 libstdc++ 使用std::string的旧实现。 It doesn't technically fully comply with C++11 and later standard revisions, but it's mostly the same.它在技术上并不完全符合 C++11 和更高版本的标准修订版,但大致相同。

Seems like you use a C++11-compatible compiler, that generates _ZN6librbd5Image6get_idEPNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE names, but your library was compiled using C++03, C++98 or something like that, before C++11.似乎您使用 C++11 兼容编译器,它生成_ZN6librbd5Image6get_idEPNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE名称,但您的库是使用 C++03、C++98 或类似的东西编译的,在 C++11 之前。

If you have access to the library sources, recompile it with C++11, if you don't, compile your program in the C++03 compatibility mode.如果您可以访问库源代码,请使用 C++11 重新编译它,如果没有,请在 C++03 兼容模式下编译您的程序。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM