目录
一、qt程序编译时调用moc
二、qmake组装makefile中的moc_*.cpp生成规则
三、通过qt工程文件向moc传入参数
qtcreator对qt程序的编译过程是先“qmake” ,然后“构建(等价于make)”。
qtcreator右键点击项目 出现的 “执行qmake”和“构建” 两个选项其实就是运行 项目-》build->构建步骤 中的“qmake”和“make”步骤所对应的命令行命令。
从项目->build->构建步骤可以看出,构建过程中先用qmake生成makefile,构建(make)过程用jom和前面产生的makefile生成目标程序的exe。jom按makefile规则的运行过程中根据依赖会先调用moc.exe生成moc_*.cpp文件,然后是按正常C++编译过程进行C++预编译(宏替换),再然后是C++编译。也就是说moc生成moc_*.cpp代码是在C++编译器进行预编译之前!
jom具体如何调用moc的过程请参考下面链接中的 构建步骤 部分:qt 工程构建过程 默认构建路径设置 通过Dos窗口 命令行 编译qt工程_丘上人的博客-CSDN博客
qmake 组装makefile中的moc_*.cpp生成规则的调用堆栈如下:
qmake组装moc_*.cpp生成规则调用堆栈//E:\workspace\QtWork\qmake\generators\makefile.cpp
QString
MakefileGenerator::replaceExtraCompilerVariables(
const QString &orig_var, const QStringList &in, const QStringList &out, ReplaceFor forShell)
{
......
if(val.isEmpty() && var.startsWith(QLatin1String("QMAKE_FUNC_"))) {
const ProKey funcname = var.mid(11).toKey();
val += project->expand(funcname, QList() << ProStringList(in) << ProStringList(out));
}
......
-----------------------------------------------
//E:\workspace\QtWork\qmake\project.cpp
QStringList QMakeProject::expand(const ProKey &func, const QList &args)
{
......
QHash::ConstIterator it =
m_functionDefs.replaceFunctions.constFind(func);
if (it != m_functionDefs.replaceFunctions.constEnd()) {
ProStringList ret;
if (evaluateFunction(*it, args, &ret) == QMakeProject::ReturnError)
exit(3);
return ret.toQStringList();
}
....
}
.....
-------------------------
//E:\workspace\QtWork\qmake\library\qmakeevaluator.cpp
......
QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateFunction(
const ProFunctionDef &func, const QList &argumentsList, ProStringList *ret)
{
VisitReturn vr;
if (m_valuemapStack.count() >= 100) {
evalError(fL1S("Ran into infinite recursion (depth > 100)."));
vr = ReturnFalse;
} else {
m_valuemapStack.push(ProValueMap());
m_locationStack.push(m_current);
ProStringList args;
for (int i = 0; i < argumentsList.count(); ++i) {
args += argumentsList[i];
m_valuemapStack.top()[ProKey(QString::number(i+1))] = argumentsList[i];
}
m_valuemapStack.top()[statics.strARGS] = args;
m_valuemapStack.top()[statics.strARGC] = ProStringList(ProString(QString::number(argumentsList.count())));
vr = visitProBlock(func.pro(), func.tokPtr());
if (vr == ReturnReturn)
vr = ReturnTrue;
if (vr == ReturnTrue)
*ret = m_returnValue;
m_returnValue.clear();
m_current = m_locationStack.pop();
m_valuemapStack.pop();
}
return vr;
}
.......
调用的部分代码如上:replaceExtraCompilerVariables()中传入expand函数的变量funcname值为:mocCmdBase,expand内部调用evaluateFunction,该函数作用是调用 用qmake language写的replace函数。也就是说断点处的目的是调用qmake language写的函数mocCmdBase()。
找到配置文件中的mocCmdBase()函数代码如下:
//QtInstallDir\Qt5.12.0\5.12.0\msvc2015_64\mkspecs\features\moc.prf
.......
defineReplace(mocCmdBase) {
!isEmpty(WIN_INCLUDETEMP) {
incvar = @$$shell_quote($$WIN_INCLUDETEMP)
} else {
incvar =
for (inc, MOC_INCLUDEPATH): \
incvar += -I$$shell_quote($$inc)
incvar += $$QMAKE_FRAMEWORKPATH_FLAGS
}
RET = $$QMAKE_MOC $(DEFINES)
msvc: RET += --compiler-flavor=msvc
isEmpty(MOC_PREDEF_FILE): RET += $$join(QMAKE_COMPILER_DEFINES, " -D", -D)
else: RET += --include $$shell_quote($$absolute_path($$moc_predefs.output, $$OUT_PWD))
RET += $$incvar $$QMAKE_MOC_OPTIONS
return($$RET)
}
.......
可以将上面的mocCmdBase中的RET与下面具体的moc_*.cpp生成规则做一下对照,QMAKE_MOC_OPTIONS是在某个prf或pri或conf配置文件中用qmake language预定义全局变量,表示传递给moc的参数,在pro中可以使用:
D:\Qt\Qt5.12.0\5.12.0\msvc2015_64\bin\moc.exe $(DEFINES) --compiler-flavor=msvc --include E:/workspace/QtWork/build-plugandpaint-Desktop_Qt_5_12_0_MSVC2015_64bit-Debug/plugins/extrafilters/debug/moc_predefs.h -ID:/Qt/Qt5.12.0/5.12.0/msvc2015_64/mkspecs/win32-msvc -IE:/workspace/QtWork/plugandpaint/plugins/extrafilters -IE:/workspace/QtWork/plugandpaint/app -ID:/Qt/Qt5.12.0/5.12.0/msvc2015_64/include -ID:/Qt/Qt5.12.0/5.12.0/msvc2015_64/include/QtWidgets -ID:/Qt/Qt5.12.0/5.12.0/msvc2015_64/include/QtGui -ID:/Qt/Qt5.12.0/5.12.0/msvc2015_64/include/QtANGLE -ID:/Qt/Qt5.12.0/5.12.0/msvc2015_64/include/QtCore -I. -I"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE" -I"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\ATLMFC\INCLUDE" -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.14393.0\ucrt" -I"C:\Program Files (x86)\Windows Kits\NETFXSDK\4.6\include\um" -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.14393.0\shared" -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.14393.0\um" -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.14393.0\winrt" -M yy=ttet ..\..\..\plugandpaint\plugins\extrafilters\extrafiltersplugin.h -o debug\moc_extrafiltersplugin.cpp
知道了moc的调用和组装规则,及相应逻辑,通过pro文件对moc传入参数就变得很显而易见了
直接在pro文件中加入如下代码:
QMAKE_MOC_OPTIONS = "-M yy=ttet"
通过pro文件对moc传递参数 pro文件设置moc参数后会写入到生成的makefile.debug中
最终生成的qt_pluginMetaData[]会变成如下:
//moc_*.cpp
QT_PLUGIN_METADATA_SECTION
static constexpr unsigned char qt_pluginMetaData[] = {
'Q', 'T', 'M', 'E', 'T', 'A', 'D', 'A', 'T', 'A', ' ', '!',
// metadata version, Qt version, architectural requirements
0, QT_VERSION_MAJOR, QT_VERSION_MINOR, qPluginArchRequirements(),
0xbf,
// "IID"
0x02, 0x78, 0x1c, 'E', 'x', 'a', 'm', 'p',
'l', 'e', 's', '.', 'P', 'l', 'u', 'g',
'i', 'n', '.', 'C', 'a', 'l', 'I', 'n',
't', 'e', 'r', 'f', 'a', 'c', 'e',
// "className"
0x03, 0x69, 'C', 'a', 'l', 'P', 'l', 'u',
'g', 'i', 'n',
// "MetaData"
0x04, 0xa2, 0x62, 'i', 'd', 0x78, 0x1c, 'E',
'x', 'a', 'm', 'p', 'l', 'e', 's', '.',
'P', 'l', 'u', 'g', 'i', 'n', '.', 'C',
'a', 'l', 'I', 'n', 't', 'e', 'r', 'f',
'a', 'c', 'e', 0x64, 'n', 'a', 'm', 'e',
0x69, 'C', 'a', 'l', 'P', 'l', 'u', 'g',
'i', 'n',
// command-line "yy"
0x62, 'y', 'y', 0x81, 0x64, 't', 't', 'e',
't',
0xff,
};
QT_MOC_EXPORT_PLUGIN(CalPlugin, CalPlugin)
另外还可以通过Q_PLUGIN_METADATA所绑定的json文件传递meta内容到qt_pluginMetaData中参考如下:
Q_PLUGIN_METADATA Q_INTERFACE Q_DECLARE_INTERFACE qt_pluginMetaData_丘上人的博客-CSDN博客_q_plugin_metadata
moc所支持的参数