在Qt中,直接include <moc_xxxxx.cpp> 为什么不会出现符号冲突的错误?

发布于:2024-07-01 ⋅ 阅读:(22) ⋅ 点赞:(0)

在逛Qt官方社区的时候看到这样一个帖子:
https://forum.qt.io/topic/117973/how-does-include-moc_-cpp-work
大概的意思是moc_xxx.cpp如果已经被编译器编译,那么在另一个cpp文件中include同一个moc_xxx.cpp应该出现符号冲突才对,但是Qt却能正确运行。对于这个问题,@KH-219Design的回答是:

qmake 负责处理这个场景的编译问题。它会扫描cpp代码和 *.pro 文件以生成 Makefile。如果在编译器和链接器遵循在Makefile中包含的 “Automatic MOC”时,当在源代码中没有找到 #include “moc_myclass.cpp” 时,会修改makefile以包含moc_myclass.cpp:
*.o 文件:

> SOURCES       = ../src/main.cpp \
>                 ../src/myclass.cpp moc_myclass.cpp 
>                 OBJECTS       = main.o \
>                 myclass.o \
>                 **moc_myclass.o** 

当#include 了 moc 文件时,qmake 会扫描到,并相应地调整 Makefile,移除moc_myclass.cpp:

> SOURCES       = ../src/main.cpp \
>                 ../src/myclass.cpp OBJECTS       = main.o \
>                 myclass.o

可见qmake非常智能。

笔者使用cmake的工程对qmake的这个特性进行验证,发现其设计也更为巧妙。

首先,在使用了Q_OBJECT类的源码中,增加一行:
在这里插入图片描述
在CMake的Qt项目中,qmake会将一个工程的所有moc_xxx.cpp放在同一个文件中包含,例如:
XXX_autogen\mocs_compilation_Release.cpp,这个文件内容如下:
在这里插入图片描述

这样的好处是在新增Q_OBJECT类的时候,不需要修改cmakelist或者改变构建工具的行为。

接下来,我们对比//#include <moc_xxCardObjBase.cpp>注释前和注释后的区别。发现如果在源码直接包含moc_xxCardObjBase.cpp时,mocs_compilation_Release.cpp文件内容确实少了 include <2FELSIXJDY/moc_xxCardObjBase.cpp>。所以qmake确实会扫描源文件中,include<moc_xxx.cpp>的行为!!
在这里插入图片描述

这个过程中,注意到XXX_autogen\include_Debug下新生成了moc_XXCardObjBase.cpp,这个文件和之前生成的moc_XXCardObjBase.cpp.d目录不一样,之前生成的在2FELSIXJDY子目录下。
在这里插入图片描述
出于好奇也对比了这两个文件的内容,对比了moc_XXCardObjBase.cpp与2FELSIXJDY/moc_XXCardObjBase.cpp两个文件,发现其内容几乎一模一样,只有头文件的include路径变了。因为这个头文件采用的是相对路径,如果不变,会导致编译不过。
在这里插入图片描述
所以,假如我们自作聪明,直接在cpp里写#include <2FELSIXJDY/moc_XXCardObjBase.cpp>,那么反而会遇到路径错误,试了一下,果然如此。

更进一步

想要进一步了解Qt MOC的技术细节,请移步:《探究Qt5【元对象编译器,moc】的 原理和技术细节