странная неопределенная ссылка на `vtable - PullRequest
12 голосов
/ 15 мая 2019

Я поймал в ловушку "undefined reference to vtable..." на целый день.

На самом деле, я видел много ответов на вопрос "undefined reference to vtable..."

Например:

неопределенная ссылка на vtable "Транзакция"

Неопределенная ссылка на vtable

https://gcc.gnu.org/faq.html#vtables

Неопределенная ссылка на vtable

Одни люди забывают написать виртуальную функцию, другие забывают добавить файл .cpp в каталог сборки. Но я думаю, что заметил это.

Я хочу сделать следующий шаг:

  • Я хочу скомпилировать класс A_1 и A_2 в общую библиотеку libA. A_2 является производным от A_1.

A_1.h

#ifndef include_A_1_h
#define include_A_1_h
class A_1
{
public:
    A_1() {}
    virtual ~A_1() {} // not pure-virtual function has defined
    virtual void print() = 0;

private:
};
#endif

A_2.h

#ifndef include_A_2_h
#define include_A_2_h
#include "A_1.h"

class A_2 : public A_1
{
public:
    A_2() {}
    ~A_2() {}
    virtual void print();

private:
};
#endif

A_2.cpp

#include "A_2.h"

void A_2::print()
{
    // empty
}
  • Я хочу скомпилировать класс B_1 и B_2 в общую библиотеку libB. B_1 и B_2 независимы.

B_1.h

#ifndef include_B_1_h
#define include_B_1_h

#include <iostream>
#include <string.h>

class B_1
{
public:
    B_1(const std::string &path);
    ~B_1();

private:
};
#endif

B_1.cpp

#include "B_1.h"

B_1::B_1(const std::string &path)
{
}

B_1::~B_1()
{
}

B_2.h

#ifndef include_B_2_h
#define include_B_2_h

class B_2
{
public:
    B_2() {}
    ~B_2() {}
    void fun();

    private:
    };

#endif

B_2.cpp

#include "B_2.h"
#include "A_1.h"
#include "A_2.h"

void B_2::fun()
{
    A_1 *ptr = new A_2;
}
  • Я хочу использовать две общие библиотеки в main.cpp. Здесь что-то идет не так.

main.cpp

#include "B_1.h"
int main()
{
    B_1 b1("name");
}

Я использую следующую команду для компиляции:

g++ A_2.cpp -fPIC -shared -o libA.so
g++ B_1.cpp B_2.cpp -fPIC -shared -o libB.so
g++ main.cpp -L . -lA -lB

Компилятор сказал, что:

./libB.so: undefined reference to `vtable for A_2'

Вы можете увидеть много пустых функций, потому что я игнорирую какой-то нерелевантный код. Но в этом случае все равно есть ошибка.

Может ли кто-нибудь мне помочь? Спасибо.

1 Ответ

10 голосов
/ 15 мая 2019

Предоставьте также общую библиотеку A при компиляции библиотеки B.

g++ B_1.cpp B_2.cpp  -L . -lA  -fPIC -shared -o libB.so

Проще говоря (я не эксперт в данной теме), компоновщик ld, используемый g ++ под капотом, сообщает о неопределенных символах. При компиляции main неразрешенные символы в libB не разрешаются путем предоставления libA, поскольку все символы, используемые явно main, разрешаются с использованием libB.

По умолчанию:

  • при компиляции исполняемого файла ld завершается ошибкой, если есть неопределенные символы
  • при компиляции библиотеки ld не завершится ошибкой, если есть неопределенные символы

Последние позволяют выполнять множество гибких задач, в том числе циклические зависимости между библиотеками (здесь libA также может зависеть от libB).

Чтобы потерпеть неудачу на втором шаге, вам нужно явно указать компоновщику, что он потерпит неудачу, если есть неопределенные символы, используя -z defs.

g++ B1.cpp B2.cpp -z defs -fPIC -shared -o libB.so

/ tmp / cchjkdnAk.o: в функции A_2::A_2()': B2.cpp:(.text._ZN3A_2C2Ev[_ZN3A_2C5Ev]+0x1b): undefined reference to vtable для A_2 'collect2: ошибка: ld вернул 1 состояние выхода

Ваша директива компиляции работала бы, если бы main.cpp был записан как:

#include "A_2.h"
#include "B_1.h"
int main()
{
    A_1 *ptr = new A_2;
    B_1 b1("name");
}

libA была бы загружена для разрешения символов в main, и эти символы использовались бы для отсутствующих символов libB.

для получения дополнительной информации: в журнале Linux есть прекрасная статья, в которой подробно рассматривается разрешение символов

...