首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >对类成员函数的c++未定义引用

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

Stack Overflow用户
提问于 2020-03-31 03:00:08
回答 2查看 172关注 0票数 3

我在尝试使用librbd时遇到了以下链接问题。

下面是我的代码片段。

  • main.cc
代码语言:javascript
复制
#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;
}

使用以下命令编译时发生错误

代码语言:javascript
复制
$ 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

但是我使用nm来证明get_id的存在:

代码语言:javascript
复制
$ nm -D /usr/lib64/librbd.so | grep get_id
0000000000083d00 T rbd_get_id
000000000008de10 T _ZN6librbd5Image6get_idEPSs
                 U _ZN8librados7v14_2_05IoCtx6get_idEv

它在全球范围内是可见的:

代码语言:javascript
复制
$ 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

为什么在编译时出现错误:对librbd::Image::get_id的未定义引用。它显然存在,这让我很好奇。

EN

回答 2

Stack Overflow用户

发布于 2020-03-31 03:31:11

一些背景: C++11通过向几个成员函数添加noexcept说明符,稍微改变了std::string接口,但事实证明,微小的变化意味着libstdc++必须以不兼容ABI的方式重写它们的std::string实现。为了向后兼容,他们保留了旧版本,并将新版本放在内联命名空间中,因此就链接器而言,它被命名为std::__cxx11::basic_string。有关更多信息,请参见此页

那就是你遇到麻烦的地方。_ZN6librbd5Image6get_idEPSs解记

代码语言:javascript
复制
librbd::Image::get_id(
    std::basic_string<
        char,
        std::char_traits<char>,
        std::allocator<char>
    >*
)

该函数接受旧版本的std::string,但您将向它传递指向新版本的std::string的指针。想必你所拥有的图书馆员的版本要么是用GCC的旧版本建造的,要么是故意针对旧的ABI而建的。

您有几种方法可以解决这一问题:

  1. 查找为libstdc++的新ABI. 构建的图书库的一个版本。
    • 如果您使用的版本来自发行版的包管理器,您可能需要在其他地方查找(比如Conan或vcpkg之类的东西)。

  1. 用新的ABI来建立自己的图书馆。
    • 我不熟悉那个图书馆,所以我不知道这有多难。似乎在某些发行版上,它们的工具链防止它

  1. 根据旧的ABI构建应用程序。
    • 正如我上面链接的页面所述,您可以将_GLIBCXX_USE_CXX11_ABI预处理宏定义为0,以告诉libstdc++使用std::string的旧实现。它在技术上并不完全符合C++11和以后的标准修订,但基本上是一样的。

票数 5
EN

Stack Overflow用户

发布于 2020-03-31 03:14:48

似乎您使用了一个与C++11兼容的编译器,它生成_ZN6librbd5Image6get_idEPNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE名称,但是在C++11之前,您的库是使用C++03、C++98或诸如此类的语言编译的。

如果您可以访问库源,请使用C++11重新编译它,如果没有,则以C++03兼容性模式编译程序。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60942781

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档