簡體   English   中英

c ++對類成員函數的未定義引用

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

我在嘗試使用 librbd 時遇到了以下鏈接問題。

以下是我的代碼片段。

  • 主文件
#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;
}

我使用以下命令編譯時發生錯誤

$ 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 存在:

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

它是全球可見的:

$ 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 它顯然存在,這讓我感到奇怪。

一些背景:C ++ 11改變了std::string ,加入稍接口noexcept符的幾個成員函數,但事實證明,細微的變化意味着的libstdc ++不得不重新編寫他們std::string實現在非ABI 兼容方式。 為了向后兼容,他們保留了舊版本並將新版本放在一個內聯命名空間中,因此就鏈接器而言,它被命名為std::__cxx11::basic_string 有關更多信息,請參閱此頁面

這就是你遇到麻煩的地方。 _ZN6librbd5Image6get_idEPSs

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

該函數接受舊版本的std::string ,但您將指針傳遞給新版本的std::string 據推測,您擁有的 librbd 版本要么是用舊版本的 GCC 構建的,要么是專門針對舊 ABI 構建的。

您有幾個選項可以解決此問題:

  1. 查找為 libstdc++ 的新 ABI 構建的 librbd 版本。
    • 如果您使用的版本來自發行版的包管理器,您可能需要查看其他地方(例如 Conan 或 vcpkg 或其他東西)。
  2. 自己針對新的 ABI 構建 librbd。
    • 我不熟悉那個圖書館,所以我不知道這會有多難。 似乎在某些發行版上,他們的工具鏈阻止了它
  3. 針對舊的 ABI 構建您的應用程序。
    • 正如我上面鏈接的頁面所說,您可以將_GLIBCXX_USE_CXX11_ABI預處理器宏定義為0以告訴 libstdc++ 使用std::string的舊實現。 它在技術上並不完全符合 C++11 和更高版本的標准修訂版,但大致相同。

似乎您使用 C++11 兼容編譯器,它生成_ZN6librbd5Image6get_idEPNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE名稱,但您的庫是使用 C++03、C++98 或類似的東西編譯的,在 C++11 之前。

如果您可以訪問庫源代碼,請使用 C++11 重新編譯它,如果沒有,請在 C++03 兼容模式下編譯您的程序。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM