无法在CMake项目中使用Q_OBJECT宏 [英] fail to use Q_OBJECT Macro in CMake Project

查看:251
本文介绍了无法在CMake项目中使用Q_OBJECT宏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在CMake项目中遇到了Qt的元对象编译器的问题。我正在构建的共享库包含以下代码,并使用pimpl习惯用法。调用CMake并编译后,我得到

I am having trouble with the meta Object Compiler of Qt in my CMake Project. A shared lib I am building contains the following code and employs the pimpl idiom. After invoking CMake and upon compilation I get


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'的配方失败

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宏合并到我的项目中的正确方法是什么。请帮助= /

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. Please help =/

gui / include / gui / mainWindow.hpp

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

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_);
}

我这样编译libray:

I compile the libray like so:

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)

现在我想将此lib与我的可执行文件链接

Now I want to link this lib against my executable

apps / main.cpp

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,其中我链接到gui lib

with the following CMakelists.txt where I link against the 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)

我的顶级CMake项目列表如下所示

my top-level CMakeLists of the project looks like the following

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

It is a typical confusion about compiling Qt application with CMake. Basically there are two approaches to run moc preprocessor with CMake:

它非常易于使用,但有一些文档中提到的要求。

It is very easy to use but has a couple of requirements which are mentioned in the documentation.


  • 确保为目标启用属性 AUTOMOC

set_target_properties(${PROJECT_NAME} PROPERTIES AUTOMOC TRUE)


  • 如果您的 .cpp 文件包含 Q_OBJECT 宏,则需要包括生成的<$ c $最后一个qobject类之后的c> .moc 文件(最好在文件末尾)。对于此步骤,您还需要启用 CMAKE_INCLUDE_CURRENT_DIR ,但这是任何CMake + Qt构建的一般建议。

  • 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). For this step you also need to enable CMAKE_INCLUDE_CURRENT_DIR but it is a general recommendation for any CMake+Qt build.

    如果头文件包含 Q_OBJECT ,请确保CMake知道它。最简单的方法是与源文件一起传递:

    If your header file contains Q_OBJECT make sure CMake knows about it. The easiest way is to pass along with the source files:

    add_library(${PROJECT_NAME}
      SHARED
       include/mainWindow.hpp
       src/mainWindow.cpp
    )
    


  • 最后链接所有必需的Qt库。

  • And finally link all required Qt libraries.

    target_link_libraries(${PROJECT_NAME}
      PUBLIC
       Qt5::Widgets
       Qt5::Core
    )
    


  • 因此以CMake的方式修复代码:

    So to fix your code in CMake's way:

    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。使用 QT5_WRAP_CPP 的Qt方法a>



    这里,您只需要包装所有包含 Q_OBJECT 的头文件,并添加结果到源文件列表中。

    2. Qt approach with 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.

    或者,如果您在cpp文件中有一个类,它将变得很棘手。 Q_OBJECT 宏将成员函数添加到类中。在类主体之外的任何类成员函数的实现都需要知道类声明。这些实现位于生成的 .moc 文件中,但看不到类的声明。修复此问题最简单的方法是将您的 .cpp 文件拆分为两个文件:

    Or if you have a class in cpp file it gets tricky. The Q_OBJECT macro adds member functions to the class. 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. The easiest way to fix it would be to split your .cpp file into two:

    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_);
    }
    

    并将附加标头包含在 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
    )
    






    注意!注意 moc 以及使用复杂语法的类,因为限制


    Note! Be careful with moc and classes that use complex syntax as there are limitations.

    这篇关于无法在CMake项目中使用Q_OBJECT宏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆