无法在 CMake 项目中使用 Q_OBJECT 宏
fail to use Q_OBJECT Macro in CMake Project
我在使用 CMake 项目中的 Qt 元对象编译器时遇到问题。我正在构建的共享库包含以下代码并使用了 pimpl 习惯用法。在调用 CMake 并进行编译后,我得到
AUTOGEN: error: ~/tools/Project/gui/src/mainWindow.cpp: The
file contains a Q_OBJECT macro, but does not include "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
我不明白我做错了什么,也不知道在我的项目中将 src 文件与 Q_OBJECT 宏合并的正确方法是什么。请帮忙=/
gui/include/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
#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)
现在我想link这个库针对我的可执行文件
apps/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 其中我 link 反对 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)
我的项目的顶级 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)
这是典型的用CMake编译Qt应用的困惑。
基本上有两种使用 CMake 运行 moc
预处理器的方法:
1。 CMake 的方法 AUTOMOC
属性.
它非常易于使用,但有几个要求,这些要求在文档中有所提及。
确保为目标启用 属性 AUTOMOC
。
set_target_properties(${PROJECT_NAME} PROPERTIES AUTOMOC TRUE)
如果您的 .cpp
文件包含 Q_OBJECT
宏,那么您需要在最后一个 qobject class 之后包含生成的 .moc
文件(最好是文件末尾)。对于此步骤,您还需要启用 CMAKE_INCLUDE_CURRENT_DIR
,但这是对任何 CMake+Qt 构建的一般建议。
如果您的 header 文件包含 Q_OBJECT
,请确保 CMake 知道它。最简单的方法是与源文件一起传递:
add_library(${PROJECT_NAME}
SHARED
include/mainWindow.hpp
src/mainWindow.cpp
)
最后 link 所有需要的 Qt 库。
target_link_libraries(${PROJECT_NAME}
PUBLIC
Qt5::Widgets
Qt5::Core
)
因此,以 CMake 的方式修复您的代码:
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:
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。使用 QT5_WRAP_CPP
的 Qt 方法
在这里,您只需要 "wrap" 所有 header 个包含 Q_OBJECT
的文件,并将结果添加到源文件列表中。
或者,如果您在 cpp 文件中有一个 class,它就会变得棘手。 Q_OBJECT
宏将成员函数添加到 class。 class body 之外的任何 class 成员函数的实现都需要知道 class 声明。这些实现在生成的 .moc
文件中,但它们看不到 class 的声明。修复它的最简单方法是将 .cpp
文件分成两个:
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:
#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
中包含额外的 header:
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
)
注意! 注意使用复杂语法的 moc
和 classes,因为有 limitations.
我在使用 CMake 项目中的 Qt 元对象编译器时遇到问题。我正在构建的共享库包含以下代码并使用了 pimpl 习惯用法。在调用 CMake 并进行编译后,我得到
AUTOGEN: error: ~/tools/Project/gui/src/mainWindow.cpp: The file contains a Q_OBJECT macro, but does not include "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
我不明白我做错了什么,也不知道在我的项目中将 src 文件与 Q_OBJECT 宏合并的正确方法是什么。请帮忙=/
gui/include/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
#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)
现在我想link这个库针对我的可执行文件
apps/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 其中我 link 反对 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)
我的项目的顶级 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)
这是典型的用CMake编译Qt应用的困惑。
基本上有两种使用 CMake 运行 moc
预处理器的方法:
1。 CMake 的方法 AUTOMOC
属性.
它非常易于使用,但有几个要求,这些要求在文档中有所提及。
确保为目标启用 属性
AUTOMOC
。set_target_properties(${PROJECT_NAME} PROPERTIES AUTOMOC TRUE)
如果您的
.cpp
文件包含Q_OBJECT
宏,那么您需要在最后一个 qobject class 之后包含生成的.moc
文件(最好是文件末尾)。对于此步骤,您还需要启用CMAKE_INCLUDE_CURRENT_DIR
,但这是对任何 CMake+Qt 构建的一般建议。如果您的 header 文件包含
Q_OBJECT
,请确保 CMake 知道它。最简单的方法是与源文件一起传递:add_library(${PROJECT_NAME} SHARED include/mainWindow.hpp src/mainWindow.cpp )
最后 link 所有需要的 Qt 库。
target_link_libraries(${PROJECT_NAME} PUBLIC Qt5::Widgets Qt5::Core )
因此,以 CMake 的方式修复您的代码:
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:
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。使用 QT5_WRAP_CPP
的 Qt 方法
在这里,您只需要 "wrap" 所有 header 个包含 Q_OBJECT
的文件,并将结果添加到源文件列表中。
或者,如果您在 cpp 文件中有一个 class,它就会变得棘手。 Q_OBJECT
宏将成员函数添加到 class。 class body 之外的任何 class 成员函数的实现都需要知道 class 声明。这些实现在生成的 .moc
文件中,但它们看不到 class 的声明。修复它的最简单方法是将 .cpp
文件分成两个:
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:
#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
中包含额外的 header:
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
)
注意! 注意使用复杂语法的 moc
和 classes,因为有 limitations.