qmake source code 解读
创始人
2024-03-18 14:50:25

qmake的主要功能执行入口在main.cpp中的runQMake(int argc, char **argv)中。其主要框架如下:

runQMake(int argc, char **argv){QMakeVfs vfs;   //初始化qmake的文件系统。virtual file system。vfs会为每个文件赋予一个id,并提供根据id进行操作的函数。Option::vfs = &vfs;    QMakeGlobals globals;Option::globals = &globals;  globalst提供配置查询环境参数和操作环境变量相关的一些函数。.......Option::init(argc, argv); //初始化参数.....QMakeProperty prop; //初始化property。构造函数中调用QMakeProperty 的reload函数。....QMakeParser parser(&proFileCache, &vfs, &Option::evalHandler);//创建parser对象,parser的主要作用是将脚本代码转换成ProToken类型的数据,并存放到Profile对象中的m_proitems中。Option::parser = &parser;......QMakeProject project;//创建qmake工程,构造函数参数会使用到option::parser,并赋予成员变量其m_parser,结构中的成员最终用于辅助生成makefile//QMakeProject::QMakeProject(): QMakeEvaluator(Option::globals, Option::parser, Option::vfs, &Option::evalHandler){}  .......project.read(fn)  //加载和解析(词法语法语义)配置文件(.prl、pri、.conf、.prf),解析工程pro文件......MetaMakefileGenerator *mkfile = MetaMakefileGenerator::createMetaGenerator(&project,         QString(), false, &success); //创建makefile对象向,内部通过生成SubdirsMetaMakefileGenerator或BuildsMetaMakefileGenerator对象,初始化并返回。.....mkfile->write() //生成Makefile.Debug、Makefile.Release、Makefile三个文件。
}

QMakeProject是整体的架构,他继承与QMakeEvaluator,用于描述一个qt工程,除了完成处理语法和语义分析的QMakeEvaluator的功能,还会做一些工程相关的处理(比如路径、缓存文件)。一个QMakeProject对象含有一个用于处理词法分析的QMakeParser对象成员。QMakeProject做完解析后,作为参数传入MetaMakefileGenerator对象中,生成makefile文件。

解析从QMakeProject的read函数开始,内部会调用QMakeEvaluator::evaluateFile()。开始进行词法和语法分析。

词法分析

QMakeParser对象进行语法分析。QMakeParser主要作用是将qmake language语法的代码进行标记化(tokenized),将原始代码全部解析成ProToken类型的数据,解析内容放到Profile对象的m_proItems成员中。主要操作在QMakeParser::read中,read的调用堆栈如下:

//E:\workspace\QtWork\qmake\library\qmakeevaluator.cpp
evaluateFile是执行脚本文件的入口函数
QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateFile(const QString &fileName, QMakeHandler::EvalFileType type, LoadFlags flags)
{QMakeParser::ParseFlags pflags = QMakeParser::ParseUseCache;if (!(flags & LoadSilent))pflags |= QMakeParser::ParseReportMissing;if (ProFile *pro = m_parser->parsedProFile(fileName, pflags)) {ProStringList &tiif = m_valuemapStack.first()[ProKey("QMAKE_VISIT_FILES")];ProString tifn(fileName);if (!tiif.contains(tifn))tiif << tifn;m_locationStack.push(m_current);VisitReturn ok = visitProFile(pro, type, flags);m_current = m_locationStack.pop();pro->deref();if (ok == ReturnTrue && !(flags & LoadHidden)) {ProStringList &iif = m_valuemapStack.first()[ProKey("QMAKE_INTERNAL_INCLUDED_FILES")];ProString ifn(fileName);if (!iif.contains(ifn))iif << ifn;}return ok;} else {debugMsgInternal(0, "failed evaluateing file %s,parse error", qPrintable(fileName));return ReturnFalse;}
}--------------------------parsedProFile作用是判断文件是否已经被解析,未解析会调用readFile将文件内容读取到内存中,存放到content变量中,然后调用parsedProBlock解析读取到的代码块。
ProFile *parsedProFile(const QString &fileName, ParseFlags flags) parsedProBlock创建profile对象,对具体的代码块进行解析,然后返回profile对象
ProFile *parsedProBlock(const QStringRef &contents, int id, const QString &name, int line, SubGrammar grammar)
{ProFile *pro = new ProFile(id, name);read(pro, contents, line, grammar);return pro;
}parsedProBlock对具体的代码块进行解析,可以是一整个文件的代码,也可以是eval中传入的小片代码。
然后返回profile对象。词法分析阶段会进行字符转义操作,和预处理操作。
void QMakeParser::read(ProFile *pro, const QStringRef &in, int line, SubGrammar grammar){.....}

字符转义和部分特殊变量的预处理在这个阶段进行。引号是否缺乏以及括号是否缺乏会在这个阶段得出结果。

语法语义分析

对脚本文件的语法和语义分析用QMakeProject中的成员QMakeEvaluator对象进行处理,一个project对象只有一个QMakeEvaluator成员。在evaluateFile函数中,经过QMakeParser的解析出来的Profile传递给QMakeEaluator->visitprofile,开始对内容进行语法和语义分析。主要操作在visitProBlock中,调用堆栈如下。

 

E:\workspace\QtWork\qmake\library\qmakeevaluator.cpp
visitProfile的作用是在处理工程文件的时候预先加载背后的配置文件,以及处理不同时态(state)的命令行命令。
同时维护一个m_profileStack栈,用于存放parsed的ProFile。
QMakeEvaluator::VisitReturn QMakeEvaluator::visitProFile(ProFile *pro, QMakeHandler::EvalFileType type, LoadFlags flags){}这个visitProBlock调用下面的visitProBlock
QMakeEvaluator::VisitReturn QMakeEvaluator::visitProBlock(ProFile *pro, const ushort *tokPtr)
{m_current.pro = pro;m_current.line = 0;return visitProBlock(tokPtr);
}这个visitProBlock是进行词法和语法分析的主要逻辑。所有变量存入到m_valuemapStack中,这是一个栈和链表的功能兼有的数据结构类型的成员。
QMakeEvaluator::VisitReturn QMakeEvaluator::visitProBlock(const ushort *tokPtr)

QMakeEvaluator的几个重要数据成员

typedef QHash ProValueMap;class ProValueMapStack : public QLinkedList{}struct ProFunctionDefs {QHash testFunctions;QHash replaceFunctions;
};class QMakeEvaluator{QStack m_profileStack; // Includes onlyProValueMapStack m_valuemapStack;ProFunctionDefs m_functionDefs;
}

QMakeEvaluator::m_valuemapStack:是存放变量的键值的数据成员,他的类型如下,兼有链表和栈功能操作的数据结构类型的变量,元素类型为ProValueMap类型。ProValueMap ProKey 存放变量名,ProStringList存放变量的值(qmake language中只有字符串组的数据类型)。
QMakeEvaluator::m_functionDefs :存放自定义的replace函数和test函数。
statics.functions:存放内置的test函数。
statics.expands:存放内置的replace函数。

脚本中调用内建函数cache()函数时qmake中的调用堆栈

脚本中调用cache函数的调用堆栈
脚本中调用自定义的replace函数的调用堆栈

 
 qmake访问replace函数和test函数逻辑。

QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateExpandFunction( const ProKey &func, const ushort *&tokPtr, ProStringList *ret)  访问replace函数
{auto isbuildinE = statics.expands.constFind(func);if(isbuildinE) evaluateBuiltinExpand(*adef, func, args, *ret);   //expandVariableReferences(tokPtr, 5, &args, true);QHash::ConstIterator it =m_functionDefs.replaceFunctions.constFind(func);if(it) evaluateFunction(*it, args, ret);  //prepareFunctionArgs(tokPtr, &args);
}QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditionalFunction(const ProKey &func, const ushort *&tokPtr)  访问test函数
{auto isbuildinE = statics.functions.constFind(func);if(isbuildinT) evaluateBuiltinConditional(*adef, func, args);QHash::ConstIterator it =m_functionDefs.testFunctions.constFind(func);if(it)  evaluateBoolFunction(*it, args, func);
}

生成makefile

qmake 默认生成三个makefile相关的文件BuildsMetaMakefileGenerator::init()函数中会创建debug和release的MakefileGenerator对象,分别用于生成Makefile.Debug、Makefile.Release文件,BuildsMetaMakefileGenerator对象本身则生成Makefile文件。
具体可参考:如何通过pro文件向moc传入参数--------qmake组装makefile中的moc_*.cpp生成规则

qmake组装moc_*.cpp生成规则调用堆栈

 

编译使用到的宏开关

QT_CONFIG(process)
PROEVALUATOR_FULL 
QT_BOOTSTRAPPED 
QT_BUILD_QMAKE 
QT_NO_FOREACH 
PARSER_DEBUG

qmake 与 配置文件_丘上人的博客-CSDN博客

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...