[Qt5]CMake构建VS2015项目下开发Qt程序时用到Q_OBJECT

开发Qt程序的时候,时常要从Qt库中继续某个类,并在自定义的子类使用到 Q_OBJECT 这个宏。如果是在QtCreator中开发,当时不会遇到问题,因为QtCreator已自动实现了很多功能,这也会导致开始过程对Qt底层原理的理解。

在这里写一个MyWidget类继承Qt库中的Widget类,相关源码如下

CMakeLists.txt

cmake_minimum_required(VERSION 3.0)

project(MyWidget)

find_package(Qt5 REQUIRED Core Gui Widgets)
link_libraries(Qt5::Core Qt5::Gui Qt5::Widgets)

FILE(GLOB SC *.cpp *.h)

add_executable(${PROJECT_NAME} WIN32 ${SC})

MyWidget.h

/*MyWidget.h*/
#ifndef _MY_WIDGET_H_
#define _MY_WIDGET_H_

#include <QWidget>

class MyWidget : public QWidget 
{
	Q_OBJECT

public:
	MyWidget(QWidget *parent = 0);
	~MyWidget();
};

#endif // !_MY_WIDGET_H_

MyWidget.cpp

/*MyWidget.cpp*/
#include "MyWidget.h"
#include <QApplication>
#include <QPushButton>

MyWidget::MyWidget(QWidget *parent) : QWidget(parent)
{
	this->setMinimumSize(200, 120);
	this->setMaximumSize(200, 120);

	QPushButton *quit = new QPushButton("Quit", this);
	connect(quit, SIGNAL(clicked()), qApp, SLOT(quit()));
}

MyWidget::~MyWidget()
{
}

main.cpp

/*main.cpp*/
#include "MyWidget.h"
#include <QApplication>

int main(int argc, char** argv)
{
	QApplication app(argc, argv);

	MyWidget w;
	w.show();

	app.exec();
	return 0;
}

按以上源码使用CMake构建VS工程进行编译的时候,是会报错的:

2>MyWidget.obj : error LNK2001: 无法解析的外部符号 "public: virtual struct QMetaObject const * __thiscall MyWidget::metaObject(void)const " (?metaObject@MyWidget@@UBEPBUQMetaObject@@XZ)
2>MyWidget.obj : error LNK2001: 无法解析的外部符号 "public: virtual void * __thiscall MyWidget::qt_metacast(char const *)" (?qt_metacast@MyWidget@@UAEPAXPBD@Z)
2>MyWidget.obj : error LNK2001: 无法解析的外部符号 "public: virtual int __thiscall MyWidget::qt_metacall(enum QMetaObject::Call,int,void * *)" (?qt_metacall@MyWidget@@UAEHW4Call@QMetaObject@@HPAPAX@Z)
2>E:qtQt5LearnuildMyWidgetDebugMyWidget.exe : fatal error LNK1120: 3 个无法解析的外部命令

这上面的错误是因为前面在定义MyWidget类时,在类中添加了一个 Q_OBJECT ,作用是通过宏定义往类中添加了上面三个函数的声明,但源码中又找不到这三个函数的实现,就报错了。
那么是否可以去掉宏Q_OBJECT呢,在本例中是可以的。
但如果定义是窗口或组件类,需要自定义一些槽,那么这个Q_OBJECT就不能省略,后面再写个例程来讨论吧。
这里还是继续讨论这个报错如何处理。
其实就是用Qt中的工具moc程序进行处理,把含有Q_OBJECT宏的头文件生成所需的源码,如下:

moc MyWidget.h -o moc_MyWidget.cpp

因为这里是用cmake构建工程的,在上面的生成成功后,还需要在构建一次,把这个源码文件添加到工程里。
这里还在想办法通过cmake在工程配置中添加编译前的处理命令进行自动生成并添加到编译流程中,后面再讨论。

2021年7月22日 记

其实还有一个最简单的方法,就是在CMakeLists.txt中配置启动自动moc和其他一些操作的参数,如下:

#CMakeLists.txt
cmake_minimum_required(VERSION 3.0)

project(MyWidget)

set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)

find_package(Qt5 REQUIRED Core Gui Widgets)
link_libraries(Qt5::Core Qt5::Gui Qt5::Widgets)

FILE(GLOB SC *.cpp *.h)

add_executable(${PROJECT_NAME} WIN32 ${SC})
原文地址:https://www.cnblogs.com/dilex/p/14743240.html