首页 文章

无法在CMake项目中使用Q_OBJECT宏

提问于
浏览
2

我在我的CMake项目中使用Qt的元对象编译器时遇到了问题 . 我正在构建的共享库包含以下代码并使用了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'失败

我不知道我做错了什么或者在我的项目中使用Q_OBJECT宏合并src文件的正确方法 . 请帮忙= /

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

#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:

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链接到我的可执行文件

应用程序/ 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

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)

1 回答

  • 2

    关于使用CMake编译Qt应用程序的典型困惑 . 基本上有两种方法可以使用CMake运行 moc 预处理器:

    1. CMake使用AUTOMOC属性的方法 .

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

    • 确保为目标启用了属性 AUTOMOC .
    set_target_properties(${PROJECT_NAME} PROPERTIES AUTOMOC TRUE)
    
    • 如果 .cpp 文件包含 Q_OBJECT 宏,则需要在最后一个qobject类之后包含生成的 .moc 文件(更好地在文件末尾) . 对于此步骤,您还需要启用 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的方式修复你的代码:

    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"所有包含 Q_OBJECT 的头文件,并将结果添加到源文件列表中 .

    或者如果你在cpp文件中有一个类,它会变得棘手 . Q_OBJECT 宏将成员函数添加到类中 . 在类体外部的任何类成员函数的实现需要知道类声明 . 这些实现位于生成的 .moc 文件中,但是它们无法看到类的声明 . 解决它的最简单方法是将 .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 中包含附加 Headers :

    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! 小心使用 moc 以及使用复杂语法的类,因为limitations .

相关问题