c ++ неопределенная ссылка на функцию-член класса - PullRequest
3 голосов
/ 31 марта 2020

Я столкнулся со следующими проблемами при попытке использовать librbd.

Ниже приведен мой фрагмент кода.

  • 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;
}

Произошла ошибка, когда я скомпилировал, используя следующую команду

$ 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. Это явно существует, что заставляет меня задуматься.

Ответы [ 2 ]

5 голосов
/ 31 марта 2020

Немного предыстории: 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, которую вы имеете, была либо построена со старой версией G CC, либо специально сделана против старого ABI.

У вас есть несколько вариантов, чтобы обойти это:

  1. Найдите версию librbd, созданную для нового ABI libstdc ++.
    • Если версия, которую вы используете, взята из менеджера пакетов вашего дистрибутива, вам, возможно, придется поискать в другом месте (например, Conan или vcpkg или что-то в этом роде).
  2. Соберите librbd самостоятельно против нового ABI.
    • Я не знаком с этой библиотекой, поэтому не знаю, насколько это будет сложно. Кажется, что на некоторых дистрибутивах их цепочка инструментов предотвращает это .
  3. Создайте свое приложение против старого ABI.
    • Как сказано на странице, на которую я ссылался выше, вы можете определить макрос препроцессора _GLIBCXX_USE_CXX11_ABI для 0, чтобы указать libstdc ++ использовать старую реализацию std::string. Технически он не полностью соответствует стандарту C ++ 11 и более поздним версиям, но в основном он такой же.
0 голосов
/ 31 марта 2020

Похоже, вы используете C ++ 11-совместимый компилятор, который генерирует _ZN6librbd5Image6get_idEPNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE имен, но ваша библиотека была скомпилирована с использованием C ++ 03, C ++ 98 или чего-то подобного, до C ++ 11.

Если у вас есть доступ к источникам библиотеки, перекомпилируйте его с C ++ 11, если нет, скомпилируйте вашу программу в режиме совместимости с C ++ 03.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...