qmake source code 解读

news2024/12/30 2:31:58

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<ProKey, ProStringList> ProValueMap;

class ProValueMapStack : public QLinkedList<ProValueMap>{}

struct ProFunctionDefs {
    QHash<ProKey, ProFunctionDef> testFunctions;
    QHash<ProKey, ProFunctionDef> replaceFunctions;
};

class QMakeEvaluator{
    QStack<ProFile *> m_profileStack; // Includes only
    ProValueMapStack 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<ProKey, ProFunctionDef>::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<ProKey, ProFunctionDef>::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博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/62169.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

交通流的微观模型(Matlab代码实现)

&#x1f352;&#x1f352;&#x1f352;欢迎关注&#x1f308;&#x1f308;&#x1f308; &#x1f4dd;个人主页&#xff1a;我爱Matlab &#x1f44d;点赞➕评论➕收藏 养成习惯&#xff08;一键三连&#xff09;&#x1f33b;&#x1f33b;&#x1f33b; &#x1f34c;希…

用好单例设计模式,代码性能提升300%

目录 一次请求执行流程java代码是如何运行的&#xff1f;堆内存满了后怎么办&#xff1f;用单例模式如何优化系统性能&#xff1f; 大家好&#xff0c;今天给大家分享一个写代码的设计模式&#xff0c;就是我们最最耳熟能详的单例设计模式。 可能很多人都听说过这个单例设计模…

基于Dijkstra和A*算法的机器人路径规划(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 网络分析是GIS中非常重要的空间分析功能之一, 最短路径分析又是网络分析的核心算法, 该算法的效率决定了网络分析的功能和效率…

【CSDN】官方Markdown示例教程

这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注…

Docker学习系列3:常用命令之容器命令

本文是Docker学习系列教程中的第三篇。前几篇教程如下&#xff1a; 「图文教程」Windows11下安装Docker Desktop 「填坑」在windows系统下安装Docker Desktop后迁移镜像位置 Docker学习系列1-如何安装docker? 【Docker学习系列】Docker学习2-docker设置阿里云镜像加速器 【Doc…

简单宠物网页设计作业 静态HTML动物介绍网页作业 DW宠物网站模板下载 大学生简单野生动物网页作品代码

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

ADSP-21569/ADSP-21593的开发入门(下)

开始调试 软硬件都准备好了&#xff0c;该插的JTAG头&#xff0c;2根usb线都插好了&#xff0c;我们就开始进入调试&#xff0c;首先是要搭建软件环境。 软件用的是CCES&#xff0c;这个软件是基于Eclipse的&#xff0c;基本操作跟他都一样&#xff0c;我们首先打开软件。 他…

阿里资深架构师钟华曰:中台战略思想与架构实战;含内部实施手册

​ 编辑 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 最近在读一本书&#xff0c;叫做《企业IT架构转型之道&#xff1a;阿里巴巴中台战略思想与架构实战》&#xff0c;在写此文时本书还没有看完&#xff0c;因为担心如果把书全部看完后再来写这篇文…

Android轮播图控件com.github.pinguo-zhouwei:MZBannerView:v2.0.2

build.gradle 配置&#xff1a; dependencies { compile com.github.pinguo-zhouwei:MZBannerView:v2.0.2}xml布局&#xff1a; <com.zhouwei.mzbanner.MZBannerViewandroid:id"id/banner"android:layout_width"match_parent"android:layout_height&quo…

SpringBoot项目实现发布订阅模式,真的很简单

大家好&#xff0c;我是老三&#xff0c;在项目里&#xff0c;经常会有一些主线业务之外的其它业务&#xff0c;比如&#xff0c;下单之后&#xff0c;发送通知、监控埋点、记录日志…… 这些非核心业务&#xff0c;如果全部一梭子写下去&#xff0c;有两个问题&#xff0c;一…

python中的集合详解

目录 一.思考 二.集合 基本语法 集合的常用操作——修改 1.添加新元素 2.移除元素 3.从集合中随机取出元素 4.清空集合 5. 消除两个集合的差集 6.两个集合的合并 注意&#xff1a;集合的遍历 三.集合总结 一.思考 为什么使用集合&#xff1f; 我们目前接触到了列表、元…

php后端+JQuery+Ajax简单表单提交

通过ajax,如果从后端直接想前端返回数组,那前端收到的是一个‘Array’的字符串。所以,我比较习惯的是用json对象的格式。由后端通过json_encode()函数,把数组封装成对象,传递到前端;前端也以json的格式接收。这里用提交表单来举例说明。 页面显示如下: JQueryAjax.…

Kafka服务端参数配置

$KAFKA_HOME/config/server.properties文件中的配置 1、zookeeper.connect 该参数用于配置Kafka要连接的Zookeeper/集群的地址。它的值是一个字符串&#xff0c;使用逗号分隔Zookeeper的多个地址。Zookeeper的单个地址是host:port形式的&#xff0c;可以在最后添加Kafka在Zoo…

idea+docker+jenkins+git构建自动化部署java项目

ideadockerjenkinsgit构建自动化部署java项目 默认jenkins已经 安装jdk 9 和maven 3.5 用于 执行pom.xml 打包构建镜像 [rootECS40833040 ~]# mkdir -p /usr/local/jenkins [rootECS40833040 jenkins]# vim jenkins.sh #!/usr/bin/env bash app_name005-springboot docker …

2、JSP——配置Tomcat服务器

目录 1、下载Tomcat服务器 2、Tomcat服务器的安装 3、Tomcat的目录结构 4、配置Tomcat运行环境 4.1 右击此电脑--->属性--->高级系统设置--->环境变量 4.2 在系统变量(s)中新建--->CATALINA_HOME--->变量值为Tomcat压缩文件解压后的地址 4.3 在系统变量(s…

[附源码]计算机毕业设计线上评分分享平台Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

C语言 动态内存管理

C语言 动态内存管理引言C/C程序的内存开辟声明一、动态内存管理函数1. malloc 和 free使用示例2. calloc使用示例3. realloc使用示例4. 注意事项二、动态内存管理函数使用时的错误示范程序清单1程序清单2程序清单3程序清单4程序清单5程序清单6三、经典的内存笔试题程序清单1程序…

【可转债,股票】低频量化数据

目录历史文章股票明日涨停预测指数60日线偏离数据上证指数 MA60偏离度深证成指 MA60偏离度创业板指 MA60偏离度中小100 MA60偏离度上证50 MA60偏离度沪深300 MA60偏离度中证500 MA60偏离度中证1000 MA60偏离度科创50 MA60偏离度恒生科技 MA60偏离度恒生科技指数 MA60偏离度可转…

【强化学习论文合集 | 2018年合集】二. AAAI-2018 强化学习论文

强化学习(Reinforcement Learning, RL),又称再励学习、评价学习或增强学习,是机器学习的范式和方法论之一,用于描述和解决智能体(agent)在与环境的交互过程中通过学习策略以达成回报最大化或实现特定目标的问题。 本专栏整理了近几年国际顶级会议中,涉及强化学习(Rein…

Pytorch2.0发布了,向下兼容,加一句代码,性能翻番

概述 介绍PyTorch 2.0&#xff0c;我们迈向PyTorch下一代2系列发行版的第一步。在过去的几年里&#xff0c;我们进行了创新和迭代&#xff0c;从PyTorch 1.0到最近的1.13&#xff0c;并转移到新成立的PyTorch基金会&#xff0c;它是Linux基金会的一部分。 除了我们令人惊叹的…