简体   繁体   English

无法在CMake项目中使用Q_OBJECT宏

[英]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预处理器:

1. CMake's approach with AUTOMOC property. 1. CMake使用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
)

2. Qt approach with QT5_WRAP_CPP 2. Qt方法与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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM