[英]fail to use Q_OBJECT Macro in CMake Project
I am having trouble with the meta Object Compiler of Qt in my CMake Project. 我在我的CMake项目中使用Qt的元对象编译器时遇到了问题。 A shared lib I am building contains the following code and employs the pimpl idiom.
我正在构建的共享库包含以下代码并使用了pimpl习惯用法。 After invoking CMake and upon compilation I get
在调用CMake并编译后,我得到了
AUTOGEN: error: ~/tools/Project/gui/src/mainWindow.cpp: The file contains a Q_OBJECT macro, but does not include "mainWindow.moc" !
AUTOGEN:错误:〜/ tools / Project / gui / src / mainWindow.cpp:该文件包含一个Q_OBJECT宏,但不包含“mainWindow.moc”! gui/CMakeFiles/gui_automoc.dir/build.make:57: recipe for target 'gui/CMakeFiles/gui_automoc' failed make[2]: *** [gui/CMakeFiles/gui_automoc] Error 1 CMakeFiles/Makefile2:234: recipe for target 'gui/CMakeFiles/gui_automoc.dir/all' failed
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'失败
I dont get what I am doing wrong or whats the correct way to incorporate src files with the Q_OBJECT Macro in my project. 我不知道我做错了什么,或者在我的项目中使用Q_OBJECT宏合并src文件的正确方法是什么。 Please help =/
请帮忙= /
gui/include/gui/mainWindow.hpp GUI /包括/ GUI / mainWindow.hpp
#include <QMainWindow>
#include <string>
class MainWindow : public QMainWindow {
class MainWindowImpl;
public:
MainWindow(QWidget* parent = nullptr);
private:
MainWindowImpl* pimpl_;
};
gui/src/mainWindow.cpp GUI / 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_);
}
I compile the libray like so: 我像这样编译libray:
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)
Now I want to link this lib against my executable 现在我想将此lib链接到我的可执行文件
apps/main.cpp 应用程序/ 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();
}
with the following CMakelists.txt where I link against the gui lib 使用以下CMakelists.txt,我链接到gui lib
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)
my top-level CMakeLists of the project looks like the following 我的项目的顶级CMakeLists如下所示
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)
It is a typical confusion about compiling Qt application with CMake. 关于使用CMake编译Qt应用程序的典型困惑。 Basically there are two approaches to run
moc
preprocessor with CMake: 基本上有两种方法可以使用CMake运行
moc
预处理器:
AUTOMOC
property. AUTOMOC
属性的方法。 It is very easy to use but has a couple of requirements which are mentioned in the documentation. 它非常易于使用,但有一些文档中提到的要求。
Make sure the property AUTOMOC
is enabled for the target. 确保为目标启用了属性
AUTOMOC
。
set_target_properties(${PROJECT_NAME} PROPERTIES AUTOMOC TRUE)
If your .cpp
file contains Q_OBJECT
macro then you need to include the generated .moc
file after the last qobject class (better at the end of the file). 如果
.cpp
文件包含Q_OBJECT
宏,则需要在最后一个qobject类之后包含生成的.moc
文件(在文件末尾更好)。 For this step you also need to enable CMAKE_INCLUDE_CURRENT_DIR
but it is a general recommendation for any CMake+Qt build. 对于此步骤,您还需要启用
CMAKE_INCLUDE_CURRENT_DIR
但它是任何CMake + Qt构建的一般建议。
If your header file contains Q_OBJECT
make sure CMake knows about it. 如果您的头文件包含
Q_OBJECT
确保CMake知道它。 The easiest way is to pass along with the source files: 最简单的方法是传递源文件:
add_library(${PROJECT_NAME} SHARED include/mainWindow.hpp src/mainWindow.cpp )
And finally link all required Qt libraries. 最后链接所有必需的Qt库。
target_link_libraries(${PROJECT_NAME} PUBLIC Qt5::Widgets Qt5::Core )
So to fix your code in CMake's way: 所以以CMake的方式修复你的代码:
gui/src/mainWindow.cpp: GUI / 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"
gui/CMakeLists.txt: GUI /的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
)
QT5_WRAP_CPP
QT5_WRAP_CPP
Here you simply need to "wrap" all your header files that have Q_OBJECT
in them and add the result to the list of source files. 在这里,您只需要“包装”所有包含
Q_OBJECT
头文件,并将结果添加到源文件列表中。
Or if you have a class in cpp file it gets tricky. 或者如果你在cpp文件中有一个类,它会变得棘手。 The
Q_OBJECT
macro adds member functions to the class. Q_OBJECT
宏将成员函数添加到类中。 The implementation of any class member function outside of the class body needs to know the class declaration. 在类体外部的任何类成员函数的实现需要知道类声明。 These implementations are inside the generated
.moc
file but they cannot see the declaration of the class. 这些实现位于生成的
.moc
文件中,但是它们无法看到类的声明。 The easiest way to fix it would be to split your .cpp
file into two: 解决它的最简单方法是将
.cpp
文件拆分为两个:
gui/src/mainWindowImpl.hpp: GUI / src目录/ mainWindowImpl.hpp:
#pragma once
#include "gui/mainWindow.hpp"
class MainWindow::MainWindowImpl : public QWidget{
Q_OBJECT
public:
explicit MainWindowImpl(MainWindow *parent);
private:
MainWindow &parent_;
};
gui/src/mainWindow.cpp: GUI / 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_);
}
And include the additional header in the QT5_WRAP_CPP
: 并在
QT5_WRAP_CPP
添加其他标头:
gui/CMakeLists.txt: GUI /的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
)
Note! 注意! Be careful with
moc
and classes that use complex syntax as there are limitations . 由于存在限制 ,请注意使用复杂语法的
moc
和类。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.