Не удается использовать макрос Q_OBJECT в CMake Project
У меня проблемы с мета-объектным компилятором Qt в моем проекте CMake. Разделяемая библиотека, которую я создаю, содержит следующий код и использует идиому pimpl. После вызова CMake и после компиляции я получаю
AUTOGEN: ошибка: ~/tools/Project/gui/src/mainWindow.cpp: файл содержит макрос Q_OBJECT, но не включает "mainWindow.moc"! gui/CMakeFiles/gui_automoc.dir/build.make:57: не удалось создать рецепт для цели 'gui/CMakeFiles/gui_automoc' make[2]: *** [gui/CMakeFiles/gui_automoc] Ошибка 1 CMakeFiles/Makefile2:234: рецепт для цель 'gui/CMakeFiles/gui_automoc.dir/all' не выполнена
Я не понимаю, что я делаю неправильно или как правильно включить файлы src с макросом Q_OBJECT в мой проект. Пожалуйста, помогите =/
GUI / включать / GUI / mainWindow.hpp
#include <QMainWindow>
#include <string>
class MainWindow : public QMainWindow {
class MainWindowImpl;
public:
MainWindow(QWidget* parent = nullptr);
private:
MainWindowImpl* pimpl_;
};
гуй / SRC / mainwindow.cpp
#include "gui/mainWindow.hpp"
class MainWindow::MainWindowImpl : public QWidget{
Q_OBJECT
public:
explicit MainWindowImpl(MainWindow *parent);
private:
MainWindow &parent_;
};
MainWindow::MainWindowImpl::MainWindowImpl(MainWindow *parent)
: QWidget{parent}, parent_(*parent) {}
MainWindow::MainWindow(QWidget *parent) : QMainWindow{parent} {
pimpl_ = new MainWindowImpl{this};
setCentralWidget(pimpl_);
}
Я собираю библиотеку так:
cmake_minimum_required(VERSION 3.5.1 FATAL_ERROR)
project(gui)
QT5_WRAP_CPP(MOC_Files
include/gui/mainWindow.hpp
)
add_library(${PROJECT_NAME}
SHARED
src/mainWindow.cpp
${MOC_Files}
)
add_library(gui::gui ALIAS ${PROJECT_NAME})
target_include_directories(${PROJECT_NAME}
PUBLIC
${PROJECT_SOURCE_DIR}/include
)
set_target_properties(${PROJECT_NAME} PROPERTIES AUTOMOC TRUE)
target_link_libraries(${PROJECT_NAME}
PUBLIC
Qt5::Widgets
Qt5::Core
Qt5::Xml
Qt5::OpenGL
Qt5::Gui
)
install(TARGETS ${PROJECT_NAME} DESTINATION lib)
Теперь я хочу связать эту библиотеку с моим исполняемым файлом
Приложения / main.cpp
#include <QApplication>
#include "gui/mainWindow.hpp"
int main(int argc, char *argv[]) {
QApplication app{argc, argv};
MainWindow gui{};
gui.show();
return app.exec();
}
со следующим CMakelists.txt, где я ссылаюсь на графический интерфейс
cmake_minimum_required (VERSION 3.5.1 FATAL_ERROR)
project (app)
add_executable(${PROJECT_NAME}
main.cpp
)
target_include_directories(${PROJECT_NAME}
PUBLIC ${PROJECT_BINARY_DIR}
)
target_link_libraries(${PROJECT_NAME}
PRIVATE
gui::gui
Qt5::Widgets
Qt5::Core
Qt5::Xml
Qt5::OpenGL
Qt5::Gui
)
install(TARGETS ${PROJECT_NAME}
DESTINATION bin)
мой CMakeList верхнего уровня проекта выглядит следующим образом
cmake_minimum_required (VERSION 3.5.1 FATAL_ERROR)
project(project)
set(CMAKE_INSTALL_DIR ${PROJECT_SOURCE_DIR}/obj)
set(CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_DIR})
# add our local path to the runtime path
SET(CMAKE_INSTALL_RPATH "$ORIGIN:${CMAKE_INSTALL_PREFIX}/lib")
# also add the link paths to the runtime paths
SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
find_package(Qt5 COMPONENTS Core Widgets Xml OpenGL Gui REQUIRED)
## --> Build libraries and applications <--
add_subdirectory(gui)
add_subdirectory(apps)
1 ответ
Это типичная путаница по поводу компиляции приложения Qt с CMake. В основном есть два подхода к запуску moc
препроцессор с CMake:
1. Подход CMake с AUTOMOC
имущество.
Он очень прост в использовании, но имеет несколько требований, которые упомянуты в документации.
Убедитесь, что собственность
AUTOMOC
включен для цели.set_target_properties(${PROJECT_NAME} PROPERTIES AUTOMOC TRUE)
Если твой
.cpp
файл содержитQ_OBJECT
макрос, то вам нужно включить сгенерированный.moc
файл после последнего класса qobject (лучше в конце файла). Для этого шага также необходимо включитьCMAKE_INCLUDE_CURRENT_DIR
но это общая рекомендация для любой сборки CMake+Qt.Если ваш заголовочный файл содержит
Q_OBJECT
убедитесь, что CMake знает об этом. Самый простой способ - передать исходные файлы:add_library(${PROJECT_NAME} SHARED include/mainWindow.hpp src/mainWindow.cpp )
И, наконец, свяжите все необходимые библиотеки Qt.
target_link_libraries(${PROJECT_NAME} PUBLIC Qt5::Widgets Qt5::Core )
Итак, чтобы исправить ваш код в CMake:
гуй / SRC /mainwindow.cpp:
#include "gui/mainWindow.hpp"
class MainWindow::MainWindowImpl : public QWidget{
Q_OBJECT
public:
explicit MainWindowImpl(MainWindow *parent);
private:
MainWindow &parent_;
};
MainWindow::MainWindowImpl::MainWindowImpl(MainWindow *parent)
: QWidget{parent}, parent_(*parent) {}
MainWindow::MainWindow(QWidget *parent) : QMainWindow{parent} {
pimpl_ = new MainWindowImpl{this};
setCentralWidget(pimpl_);
}
#include "mainWindow.moc"
гуй /CMakeLists.txt:
project(gui)
set(CMAKE_INCLUDE_CURRENT_DIR YES)
add_library(${PROJECT_NAME}
SHARED
include/gui/mainWindow.hpp
src/mainWindow.cpp
)
add_library(gui::gui ALIAS ${PROJECT_NAME})
target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/include)
set_target_properties(${PROJECT_NAME} PROPERTIES AUTOMOC TRUE)
target_link_libraries(${PROJECT_NAME}
PUBLIC
Qt5::Widgets
Qt5::Core
)
2. Qt подход с QT5_WRAP_CPP
Здесь вам просто нужно "обернуть" все ваши файлы заголовков, которые имеют Q_OBJECT
в них и добавьте результат в список исходных файлов.
Или, если у вас есть класс в файле cpp, это становится сложно. Q_OBJECT
макрос добавляет функции-члены в класс. Реализация любой функции-члена класса вне тела класса должна знать объявление класса. Эти реализации находятся внутри сгенерированного .moc
файл, но они не могут видеть объявление класса. Самый простой способ исправить это было бы разделить ваш .cpp
файл на две части:
гуй / SRC /mainWindowImpl.hpp:
#pragma once
#include "gui/mainWindow.hpp"
class MainWindow::MainWindowImpl : public QWidget{
Q_OBJECT
public:
explicit MainWindowImpl(MainWindow *parent);
private:
MainWindow &parent_;
};
гуй / SRC /mainwindow.cpp:
#include "gui/mainWindow.hpp"
#include "mainWindowImpl.hpp"
MainWindow::MainWindowImpl::MainWindowImpl(MainWindow *parent)
: QWidget{parent}, parent_(*parent) {}
MainWindow::MainWindow(QWidget *parent) : QMainWindow{parent} {
pimpl_ = new MainWindowImpl{this};
setCentralWidget(pimpl_);
}
И включите дополнительный заголовок в QT5_WRAP_CPP
:
гуй /CMakeLists.txt:
project(gui)
QT5_WRAP_CPP(MOC_Files
include/mainWindow.hpp
src/mainWindowImpl.hpp
)
add_library(${PROJECT_NAME}
SHARED
src/mainWindow.cpp
${MOC_Files}
)
add_library(gui::gui ALIAS ${PROJECT_NAME})
target_include_directories(${PROJECT_NAME}
PUBLIC
${PROJECT_SOURCE_DIR}/include
)
target_link_libraries(${PROJECT_NAME}
PUBLIC
Qt5::Widgets
Qt5::Core
)
Заметка! Будь осторожен с moc
и классы, которые используют сложный синтаксис, поскольку существуют ограничения.