cmake & qt проблемы

190
02 сентября 2018, 22:10

Возникла проблема: не могу собрать проект использующий qt с помощью cmake (сам код верный, так как его можно собрать с помощью pro-file. Мой cmake-файл:

cmake_minimum_required(VERSION 3.5)
project(calculator)
add_definitions(-Wall -std=c++14)
include_directories(include)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
find_package(Qt5Widgets REQUIRED)
include_directories(Qt5Widgets_INCLUDE_DIRECTORIES)
set(MAIN_SRC sources/main.cpp)
file(GLOB CALC_SRC "sources/calc/*.cpp")
add_executable(${PROJECT_NAME} ${MAIN_SRC} ${CALC_SRC})
qt5_use_modules(${PROJECT_NAME} Widgets)

Код:

//calculator.hpp
#pragma once
#include <QWidget>
#include <QStack>
class QLCDNumber;
class QPushButton;
class Calculator : public QWidget {
    Q_OBJECT
private:
    QLCDNumber *    m_plcd;
    QStack<QString> m_stk;
    QString         m_strDisplay;
public:
    Calculator (QWidget * pwgt = 0);
    QPushButton * createButton(const QString & str);
    void         calculate();
public slots:
    void slotButtonClicked();
};

//main.cpp
#include <QApplication>
#include "calculator.hpp"
// ----------------------------------------------------------------------
int main(int argc, char** argv)
{
    QApplication app(argc, argv);
    Calculator   calculator;
    calculator.setWindowTitle("Calculator");
    calculator.resize(230, 200);
    calculator.show(); 
    return app.exec();
}
//calculator.cpp
#include <QtWidgets>
#include "calculator.hpp"
Calculator::Calculator(QWidget* pwgt/*= 0*/) : QWidget(pwgt)
{
    m_plcd = new QLCDNumber(12);
    m_plcd->setSegmentStyle(QLCDNumber::Flat);
    m_plcd->setMinimumSize(150, 50);
    QChar aButtons[4][4] = {{'7', '8', '9', '/'},
                            {'4', '5', '6', '*'},
                            {'1', '2', '3', '-'},
                            {'0', '.', '=', '+'}
                           };
    //Layout setup
    QGridLayout* ptopLayout = new QGridLayout;
    ptopLayout->addWidget(m_plcd, 0, 0, 1, 4);    
    ptopLayout->addWidget(createButton("CE"), 1, 3);
    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j) {
           ptopLayout->addWidget(createButton(aButtons[i][j]), i + 2, j);
        }
    }
    setLayout(ptopLayout);
}
QPushButton* Calculator::createButton(const QString& str)
{
    QPushButton* pcmd = new QPushButton(str);
    pcmd->setMinimumSize(40, 40);
    connect(pcmd, SIGNAL(clicked()), SLOT(slotButtonClicked()));
    return pcmd;
}

void Calculator::calculate()
{
    qreal   fOperand2    = m_stk.pop().toFloat();
    QString strOperation = m_stk.pop();
    qreal   fOperand1    = m_stk.pop().toFloat();
    qreal   fResult      = 0;
    if (strOperation == "+") {
        fResult = fOperand1 + fOperand2;
    }
    if (strOperation == "-") {
        fResult = fOperand1 - fOperand2;
    }
    if (strOperation == "/") {
        fResult = fOperand1 / fOperand2;
    }
    if (strOperation == "*") {
        fResult = fOperand1 * fOperand2;
    }
    m_plcd->display(fResult);
}
void Calculator::slotButtonClicked()
{
    QString str = ((QPushButton*)sender())->text();
    if (str == "CE") {
        m_stk.clear();
        m_strDisplay = "";
        m_plcd->display("0");
        return;
    }
    if (str.contains(QRegExp("[0-9]"))) {
        m_strDisplay += str;
        m_plcd->display(m_strDisplay.toDouble());
    }
    else if (str == ".") {
        m_strDisplay += str;
        m_plcd->display(m_strDisplay);
    }
    else {
        if (m_stk.count() >= 2) {
            m_stk.push(QString().setNum(m_plcd->value()));
            calculate();
            m_stk.clear();
            m_stk.push(QString().setNum(m_plcd->value()));
            if (str != "=") {
                m_stk.push(str);
            }
        }
        else {
            m_stk.push(QString().setNum(m_plcd->value()));
            m_stk.push(str);
            m_strDisplay = "";
        }
    }
}

На стадии линковки выдает ошибку:

CMakeFiles/calculator.dir/sources/main.cpp.o: In function `Calculator::~Calculator()':
/home/andrej/Public/example/qt_calculator/sources/main.cpp:(.text._ZN10CalculatorD2Ev[_ZN10CalculatorD2Ev]+0xb): undefined reference to `vtable for Calculator'
CMakeFiles/calculator.dir/sources/calc/Calculator.cpp.o: In function `Calculator::Calculator(QWidget*)':
/home/andrej/Public/example/qt_calculator/sources/calc/Calculator.cpp:(.text+0x58): undefined reference to `vtable for Calculator'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
CMakeFiles/calculator.dir/build.make:123: recipe for target 'calculator' failed
make[2]: *** [calculator] Error 1
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/calculator.dir/all' failed
make[1]: *** [CMakeFiles/calculator.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2
Answer 1

Здесь использованы AUTOUIC и AUTOMOC свойства, которые включают функционал CMake для генерации ui и moc. Но, чтобы они правильно работали, необходимо в списке файлов исходного кода также иметь файлы заголовков. Это нужно для того, чтобы CMake смог заглянуть в сами файлы и понять нужно ли генерировать для них ui и moc шаги компиляции.

Подробнее - в документации.

Функция qt5_use_modules депрецирована и использовать её не имеет особого смысла в современных версиях Qt. Достаточно target_link_libraries(${PROJECT_NAME} Qt5::Widgets). И вызов функции include_directories(Qt5Widgets_INCLUDE_DIRECTORIES) можно удалить потому, что target_link_libraries добавит транзитивные зависимости, которые включают пути к файлам заголовков и линковку библиотек.

Answer 2

Проблемы явно не в CMake а где-то ещё:

Я сделал папку, положил туда main.cpp и calculator.cpp/hpp, CMakeLists.txt с Вашего вопроса, открыла в qtcreator, поправил CMakeLists.txt :

set(MAIN_SRC sources/main.cpp)
file(GLOB CALC_SRC "sources/calc/*.cpp")

поменял на

set(MAIN_SRC main.cpp)
file(GLOB CALC_SRC "calc*.cpp")

собрал, запустил - результат записал и прикрепил.

READ ALSO
Как правильно преобразовать дату?

Как правильно преобразовать дату?

Есть данные в String "2018-07-09T08:26:38125+0000"

168
Как задать прозрачный фон в SurfaceView? Android

Как задать прозрачный фон в SurfaceView? Android

В приложении имеется view с графиком, поверх которой располагается другая view, потомок SurfaceViewНа SurfaceView предполагается возможность рисования...

155
POST запрос не отправляется на сервер

POST запрос не отправляется на сервер

У меня возникли проблемы с отправкой JSON на сервер, в логах видна следующая ошибка: W/Systemerr: java

175
Нельзя добавить файл в SVN в Intellij idea

Нельзя добавить файл в SVN в Intellij idea

Есть svn сервер в интернетеОткрыл idea, сделал checkout

167