Qt5 неопределенная ссылка на проблему сборки CMake vtable

#c #qt #cmake #qt5

Вопрос:

я решил создать какой-то калькулятор с помощью CMake, но по какой-то причине он не удался, но все же выглядит правильно. У меня есть правило set(CMAKE_AUTOMOC ON), и все же, что такое vtable? Я не могу просто построить его… Ниже приведены все файлы проекта

CMakeLists.txt

 cmake_minimum_required(VERSION 3.1.0)

project(calculator)

set(CMAKE_CXX_COMPILER g  )
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC_ON)
set(CMAKE_AUTORCC ON)

find_package(Qt5 COMPONENTS Core Widgets REQUIRED)

include_directories("./include")

add_executable(${PROJECT_NAME} calculator.cpp main.cpp)

target_link_libraries(${PROJECT_NAME} Qt5::Core Qt5::Widgets)

 

калькулятор.ГЭС

 #ifndef CALCULATOR_HPP
# define CALCULATOR_HPP

#include <QtWidgets/QWidget>
#include <QVector>
#include <QLCDNumber>
#include <QPushButton>

class Calculator : public QWidget {
    Q_OBJECT
public:
    Calculator(QWidget *pwgt = nullptr);
    QPushButton         *createButton(QString const amp;rhs);
    void                calculate();
private:
    QLCDNumber          *_plcd;
    QString             _strDisplay;
    QVector<QString>    _strVector;
public slots:
    void                buttonClicked();
};

#endif

 

calculator.cpp

 #include <calculator.hpp>
#include <QGridLayout>

Calculator::Calculator(QWidget *pwgt) : QWidget(pwgt) {
    QGridLayout *gridObj = new QGridLayout();

    _plcd = new QLCDNumber(12);
    _plcd->setMode(QLCDNumber::Dec);
    _plcd->setSegmentStyle(QLCDNumber::Flat);
    _plcd->setMinimumSize(150, 50);

    //_wgtPtr = (!_pwgt) ? new QWidget() : pw>
    QChar   calcChars[4][4] = { {'7', '8', '9', '/'},
                                {'4', '5', '6', '*'},
                                {'1', '2', '3', '-'},
                                {'0', '.', '=', ' '}};
    gridObj->addWidget(_plcd, 0, 0);
    gridObj->addWidget(createButton("CE"), 1, 3);
    for (int i = 0; i < 4;   i) {
        for (int j = 0;  j < 4;   j)
            gridObj->addWidget(createButton(calcChars[i][j]), i   2, j);
    }
    setLayout(gridObj);
}

QPushButton *Calculator::createButton(QString const amp;rhs) {
    QPushButton *calcButton = new QPushButton(rhs);
    calcButton->setMinimumSize(40, 40);
    connect(calcButton, SIGNAL(clicked()), SLOT(buttonClicked()));
    return (new QPushButton(rhs));
}

void        Calculator::buttonClicked() {
    QString match = dynamic_cast<QPushButton *>(sender())->text();
    QRegExp regMatch("[0-9]");

    if (!match.compare("CE")) {
        _strVector.clear();
        _strDisplay.clear();
        _plcd->display("0");
    } else if (match.contains(regMatch)) {
        _strDisplay.push_back(match);
        _plcd->display(_strDisplay.toDouble());
    } else if (!match.compare(".")) {
        _strDisplay.push_back(match);
        _plcd->display(_strDisplay.toDouble());
    } else {
        _strVector.push_back(_strDisplay);
        if (_strVector.size() > 1) {
            calculate();
            _strVector.clear();
            _strVector.push_back(_strDisplay);
            if (match.compare("="))
                _strVector.push_back(match);
        } else {
            _strVector.push_back(_strDisplay);
            _strDisplay.clear();
            _plcd->display("0");
        }
    }
}

void        Calculator::calculate() {
    double  rValue = _strVector.back().toDouble();
    _strVector.pop_back();
    QString operCalc = _strVector.back();
    _strVector.pop_back();
    double  lValue = _strVector.back().toDouble();

    if (!operCalc.compare(" "))
        rValue  = lValue;
    if (!operCalc.compare("-"))
        rValue -= lValue;
    if (!operCalc.compare("/"))
        rValue /= lValue;
    if (!operCalc.compare("*"))
        rValue *= lValue;
    _strDisplay.number(rValue);
    _plcd->display(_strDisplay.toDouble());
}
 

и main.cpp

 #include <calculator.hpp>
#include <QApplication>

int main(int argc, char *argv[]) {
    QApplication    app(argc, argv);
    Calculator  *obj = new Calculator;
    obj->resize(230, 200);
    obj->setWindowTitle("QtCalculator");
    obj->show();

    return (app.exec());
}

 

это иерархия файлов

 |--> CMakeLists.txt
|
|--> calculator.cpp
|
|--> main.cpp
|
|--> include
     |
     |--> calculator.hpp
 

И это результат сборки (в среде CLion IDE)

 ====================[ Build | all | Debug ]=====================================
/snap/clion/162/bin/cmake/linux/bin/cmake --build /home/lchantel/train_01Qt/cmake-build-debug --target all -- -j 3
[ 20%] Automatic MOC for target calculator
[ 20%] Built target calculator_autogen
Scanning dependencies of target calculator
[ 40%] Building CXX object CMakeFiles/calculator.dir/calculator_autogen/mocs_compilation.cpp.o
[ 60%] Building CXX object CMakeFiles/calculator.dir/calculator.cpp.o
[ 80%] Building CXX object CMakeFiles/calculator.dir/main.cpp.o
[100%] Linking CXX executable calculator
/usr/bin/ld: CMakeFiles/calculator.dir/calculator.cpp.o: in function `Calculator::Calculator(QWidget*)':
/home/lchantel/train_01Qt/calculator.cpp:4: undefined reference to `vtable for Calculator'
/usr/bin/ld: /home/lchantel/train_01Qt/calculator.cpp:4: undefined reference to `vtable for Calculator'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/calculator.dir/build.make:126: calculator] Error 1
make[1]: *** [CMakeFiles/Makefile2:84: CMakeFiles/calculator.dir/all] Error 2
make: *** [Makefile:91: all] Error 2
 

Комментарии:

1. Спасибо за предоставление полного примера, который позволил мне воспроизвести вашу ошибку.

Ответ №1:

Ваш код CMake нуждается в некоторой доработке:

  1. Никогда не используйте include_directories в CMake никогда. Используйте target_include_directories вместо этого.
  2. Всегда используйте один из PRIVATE PUBLIC или INTERFACE с target_link_libraries , чтобы избежать странного устаревшего поведения.
  3. Определение целей в терминах ${PROJECT_NAME} является странным, более длинным и делает ваш код менее читаемым без какой-либо пользы. Нет никаких веских причин для их соединения, и название проекта редко меняется.
  4. Никогда не садись CMAKE_CXX_COMPILER в свой CMakeLists.txt
  5. Предпочитайте функции компиляции настройке CMAKE_CXX_STANDARD .
  6. Я серьезно сомневаюсь, что вы используете CMake 3.1.0. Никогда не устанавливайте версию ниже той, с которой вы используете / тестируете.
  7. У вас есть случайное подчеркивание в CMAKE_AUTOUIC_ON

Вместо этого используйте эту сборку:

 cmake_minimum_required(VERSION 3.16)
project(calculator)

set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)

find_package(Qt5 REQUIRED Core Widgets)

add_executable(calculator calculator.cpp main.cpp include/calculator.hpp)
target_link_libraries(calculator PRIVATE Qt5::Core Qt5::Widgets)
target_include_directories(calculator PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include")
target_compile_features(calculator PRIVATE cxx_std_11)
 

Причина, по которой вы видите ошибку vtable moc , заключается в том, что она не видит ваш include/calculator.hpp заголовок, потому что он не указан в качестве одного из источников add_executable .