【问题标题】:fail to use Q_OBJECT Macro in CMake Project无法在 CMake 项目中使用 Q_OBJECT 宏
【发布时间】:2018-05-08 08:55:16
【问题描述】:

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

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

我不明白我做错了什么,或者在我的项目中将 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)

现在我想将这个库链接到我的可执行文件

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

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)

【问题讨论】:

  • 您是否尝试将行#include "mainWindow.moc" 添加到源gui/include/gui/mainWindow.cpp,如错误消息所示?
  • 我做了并且得到了 ~/tools/Project/gui/src/mainWindow.cpp:74:26: 致命错误: mainWindow.moc: 没有这样的文件或目录编译终止。 gui/CMakeFiles/gui.dir/build.make:62:目标“gui/CMakeFiles/gui.dir/src/mainWindow.cpp.o”的配方失败 make[2]:*** [gui/CMakeFiles/gui. dir/src/mainWindow.cpp.o] 错误 1
  • 您是否按照建议的here 尝试#include "gui/mainWindow.moc" 中的mainWindow.cpp
  • 我个人觉得 AUTOMOC 很挑剔,最后决定用 qt5_wrap_cpp(MOC_OUT ${INPUT}) 手动调用 moc,然后将 ${MOC_OUT} 传递到我的库或二进制文件中的源列表。您可能想尝试一下
  • 像我上面那样通过包含它来做到这一点,没有帮助

标签: c++ qt cmake qobject qmetaobject


【解决方案1】:

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

在这里,您只需“包装”所有包含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 中包含附加标头:

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 和使用复杂语法的类,如limitations

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-06-21
    • 1970-01-01
    • 2013-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多