目录
说明:该文档主要是对qmake手册做一些补充
词法
词法阶段主要作用是将原始的qmake language写的代码全部转换成ProToken类型去。并存入Profile对象中去。
qmake中词法阶段识别出的类型(token type)有这些(一共32种):
// These token definitions affect both ProFileEvaluator and ProWriter
enum ProToken {
TokTerminator = 0, // end of stream (possibly not included in length; must be zero)
TokLine, // line marker:
// - line (1)
TokAssign, // variable =
TokAppend, // variable +=
TokAppendUnique, // variable *=
TokRemove, // variable -=
TokReplace, // variable ~=
// previous literal/expansion is a variable manipulation
// - lower bound for expected output length (1)
// - value expression + TokValueTerminator
TokValueTerminator, // assignment value terminator
TokLiteral, // literal string (fully dequoted)
// - length (1)
// - string data (length; unterminated)
TokHashLiteral, // literal string with hash (fully dequoted)
// - hash (2)
// - length (1)
// - string data (length; unterminated)
TokVariable, // qmake variable expansion $$ $${}
// - hash (2)
// - name length (1)
// - name (name length; unterminated)
TokProperty, // qmake property expansion $$[]
// - hash (2)
// - name length (1)
// - name (name length; unterminated)
TokEnvVar, // environment variable expansion $$()
// - name length (1)
// - name (name length; unterminated)
TokFuncName, // replace function expansion
// - hash (2)
// - name length (1)
// - name (name length; unterminated)
// - ((nested expansion + TokArgSeparator)* + nested expansion)?
// - TokFuncTerminator
TokArgSeparator, // function argument separator
TokFuncTerminator, // function argument list terminator
TokCondition, // previous literal/expansion is a conditional
TokTestCall, // previous literal/expansion is a test function call
// - ((nested expansion + TokArgSeparator)* + nested expansion)?
// - TokFuncTerminator
TokReturn, // previous literal/expansion is a return value
TokBreak, // break loop
TokNext, // shortcut to next loop iteration
TokNot, // '!' operator
TokAnd, // ':' operator
TokOr, // '|' operator
TokBranch, // branch point:
// - then block length (2)
// - then block + TokTerminator (then block length)
// - else block length (2)
// - else block + TokTerminator (else block length)
TokForLoop, // for loop:
// - variable name: hash (2), length (1), chars (length)
// - expression: length (2), bytes + TokValueTerminator (length)
// - body length (2)
// - body + TokTerminator (body length)
TokTestDef, // test function definition:
TokReplaceDef, // replace function definition:
// - function name: hash (2), length (1), chars (length)
// - body length (2)
// - body + TokTerminator (body length)
TokBypassNesting, // escape from function local variable scopes:
// - block length (2)
// - block + TokTerminator (block length)
TokMask = 0xff,
TokQuoted = 0x100, // The expression is quoted => join expanded stringlist
TokNewStr = 0x200 // Next stringlist element
};
string
1、数据类型
qmake language中数据类型只有字符串组(stringlist)类型(但是无法直接以下标的形式访问数组中单个元素,可以通过内置函数member来获取某个元素),qmake解析字符串时以空格或者换行符作为字符串分隔符。如果要在字符串中填入空格或其他特殊字符,避免被qmake误解析,可以用双引号将字符串引用起来。
message(aa bb cc) #输出:aa bb cc
message("aa,bb,cc") #输出:aa,bb,cc message只能输入一个参数,参数以空格隔开,多余一个参数会报错
var=aa bb cc #将字符串组存放入变量var中,aa bb cc 会被解析成三个字符串
message($$var) #输出aa bb cc
message($$size(var)) #输出3,表示变量var中存放了三个字符串
var="aa bb" cc #"aa bb" cc 会被解析成两个字符串
message($$size(var)) #输出2,表示变量var中存放了两个字符串
var = "aa bb"" cc" #"aa bb"" cc" 会被解析成一个字符串
message($$size(var)) #输出1,表示变量var中存放了一个字符串
var = "aa bb" " cc" #"aa bb" " cc" 会被解析成两个字符串
message($$size(var)) #输出2,表示变量var中存放了两个字符串
var = "aa bb cc" #"aa bb cc" 会被解析成一个字符串
message($$size(var)) #输出1,表示变量var中存放了一个字符串
var = "aa" "bb" "cc" #"aa" "bb" "cc"会被解析成三个字符串
message($$size(var)) #输出3,表示变量var中存放了三个字符串
var = aa,bb #定义一个名字为var的变量,将字符串"aa,bb"赋予给它,等价于var= "aa,bb"。
message($$var) #将字符串"aa,bb"打印出来。输出aa,bb,注意此时aa,bb已经在前面赋值的时候被解析成一个字符串了,此处作为内容传递时,不会被解析成两个参数。
var+= ,cc #将字符串",cc"附加到var中。var:"aa,bb" ",cc"
message($$var) #输出:aa,bb ,cc 注意",cc"前面有一个空格
var= aa bb cc #将字符串组 aa bb cc存放到var中。var:aa bb cc
var*= aa dd #将字符串组aa dd去除与var中内容相同的字符串单元后放到var中,字符串中的内容必须以空格隔开才被当做一个字符串单元。var:aa bb cc dd
message($$var) #输出:aa bb cc dd
var-= aa cc #将与字符串组aa cc中相同单元的内容从var中存放的字符串中去除。var:bb dd
message($$var) #输出:bb dd
var = hello world,for fun
var~= s/l/t #将字符串组hello world,for fun中的第一个字符串单元中的l替换成t
message($$var) #输出:hetto world,for fun
var~= s/l/t/g #将字符串组hello world,for fun中的所有字符串单元中的l替换成t
message($$var) #输出:hetto wortd,for fun
qmake language ~= 字符串替换操作 正则表达式_丘上人的博客-CSDN博客
2、特殊处理的内置变量
_LINE_(当前行号)、_FILE_(当前文件名)、LITERAL_HASH(字符'#')、LITERAL_DOLLAR(字符'$')、LITERAL_WHITESPACE(制表符tab键'\t'),在词法阶段就直接替换成对应的值,相当于qmake language的预处理。
3、转义字符
qmake language对string中的字符转义是在词法分析阶段,转义字符包括:
//qmake QMakeParse.read中词法分析对转义操作的代码部分
else if (c == '\\') {
static const char symbols[] = "[]{}()$\\'\"";
ushort c2;
if (cur != end && !((c2 = *cur) & 0xff00) && strchr(symbols, c2)) {
c = c2;
cur++;
} else {
deprecationWarning(fL1S("Unescaped backslashes are deprecated"));
}
}
词法分析阶段不会对(\n,\t,\r)转义。如果要对(\n,\t,\r)转移,也就是获取到('\n','\r','\t'),需要用escape_expand(string)这个replace函数进行操作。('\n':换行,移动到下行;'\r':回车换行,移动到下行行首,移动到行首;'\t':tab键)
message("\[ \] \{ \} \( \) \$ \\ \' \" aa\nbb\rcc\tdd")
message($$escape_expand("\[ \] \{ \} \( \) \$ \\ \' \" aa\nbb\rcc\tdd")) #字符串“\[ \] \{ \} \( \) \$ \\ \' \" aa\nbb\rcc\tdd”在词法分析阶段就被处理成:“[ ] { } ( ) $ \ ' " aa\nbb\rcc\tdd”。escape_expand再对\n \r \t 进行转移处理。
输出:
另外在词法处理时还会兼顾行延续功能:
var = aaaa \
bbbb
message($$var) #输出Project MESSAGE: aaaa bbbb
escape_expand所做的字符转义在qmake language中不作为字符串分隔符号,参看如下代码:
var=aaa bbb
message($$size(var))
var= aaa$$escape_expand(\n)bbb
message($$size(var))
var = aaa$$escape_expand(\t)bbb
message($$size(var))
var = aaa$$escape_expand(\r)bbb
message($$size(var))
#输出:
Project MESSAGE: 2
Project MESSAGE: 1
Project MESSAGE: 1
Project MESSAGE: 1
关键字:包括语法关键字、特殊变量
qmake language 关键字 true false host_build option return next break _LINE_ _FILE_ LITERAL_HASH LITERAL_DOLLAR LITERAL_WHITESPACE CONFIG ARGS ARGC ever forever host_build TEMPLATE QMAKE_PLATFORM QMAKE_DIR_SEP QMAKESPEC REQUIRES :qmake language 关键字
语法
变量
qmake language变量分为内置变量和自定义变量,内置变量包括qmake在C++中定义的变量,和用qmake language写的配置文件定义的变量。在文档的目录:Qt 5.12->qmake Manual->Variables有对内置变量做了一些介绍。
qmake language中只有一种数据类型,字符串组(stringlist)类型。定义一个变量必须要有等号。
定义一个变量的表达式形式:variablename = [values]
var1 = aaa bbb #定义一个名字为var1的变量,用字符串组aaa bbb对其进行初始化
var2 = #定义一个名字为var2的变量,初始化为空
变量、属性、环境变量区别
qmake language(属性property、变量variable、环境变量evironment variable) 讲述$$var 、$${var}、 $$[]、 $$() 、$()的区别及使用。
变量使用
在文档目录:Qt 5.12->qmake Manual->qmake Language下有对变量使用做详细介绍
几个要点:
1、qmake language中的变量只有字符串组类型,没有bool、float、double类型!!
2、在赋值符号的右边的内容都会被当成字符串组,当在等号右边遇到$$ 符号时会提取该变量值或计算该replace函数结果后再赋值给变量。
3、双引号的作用在于传递函数参数的时候,可以将逗号作为字符串的一部分传入,但有多个函数参数时,函数参数需要用逗号隔开。
4、访问变量内容使用$$variablename 或者 $${variablename}。区别是$$var.de变量名是var.de,$${var}.de的变量名是var。 通过后者可以用于组装复杂的变量名,并获取其内容。
5、qmake language不允许变量名直接用$$ $$或$${$$}的形式直接进行嵌套。但可以通过eval(expression)这个replace函数来达到目的。注意eval函数还可以是一个test函数。qmake language eval(string) 函数_丘上人的博客-CSDN博客
qmake有提供加减运算的函数,num_add(arg1 [, arg2 ..., argn]),qmake对其实现是先将字符串转换成数值,再对数值进行操作,再将数值转换成字符串,再返回。
变量命名规则:以字母开头,后面可以有‘_’、‘.’、数字、字母,遇到其他字符表示变量命名截止。变量名区分大小写
VAR = #定义一个名字为VAR的空变量,没有定义的变量也可以被调用VAR1:
VAR1 = tt1 #定义一个名字为VAR1的变量,并将字符串tt1赋予给它,等价于VAR1="tt1"。VAR1:"tt1"
message(aa bb cc) #输出aa bb cc
message("$${VAR1} aa,bb") #输出:"tt1 aa,bb"。需要注意的是message只能输入一个参数,函数参数以逗号隔开,要让message输出逗号,需要用双引号引起来
#$$varname 与 $${varname} 都是取出变量中存放的字符串,区别是$$var.de变量名是var.de,$${var}.de的变量名是var。
VAR = 3
VAR3=vvv
vvv.a = ttttttt
VARt = $$eval(VAR$${VAR}).a
message($$VARt) #输出:vvv.a
message($$eval($$VARt)) #输出:ttttttt
message($$eval($$eval(VAR$${VAR}).a))输出:ttttttt 。 eval可以多重嵌套
#qmake language 计算加减法
first=11
second=22
sum1 = $$num_add($$first, -$$second)
second_neg = -$$second
second_neg ~= s/^--// #正则表达式"^--" 的意思是如果开头有两个符号,就将两个符号变成空,也就是消掉--
sum2 = $$num_add($$first, $$second_neg)
message("sum1=$$sum1 , sum2=$$sum2") #输出:sum1=-11 , sum2=-11
快速查找qt pro文件中的用qmake language写的库函数和变量_丘上人的博客-CSDN博客
全局变量和函数内变量作用域
qmake language中与C++或java等他语言的变量作用域有点差异,变量作用域只有全局的和函数内的。用大括号"{}"括起来的代码无法构成局部变量。具体原因可以参考:m_valuemapStack
var1 = 1111
{#与C++或java不同,单纯的大括号内定义的变量也属于全局变量
var2 = 2222
}
true:{ #条件分支中的变量也属于全局变量
var3 = 3333
}
defineTest(ptestf){ #只有函数中定义的变量的作用于才只限定在函数中。
var4 = 4444
}
defineReplace(prepf){#只有函数中定义的变量的作用于才只限定在函数中。但对变量进行export之后,该变量作用域就会变成全局作用域。
var5 = 5555
export(var5) #将函数内的变量转变为全局变量。
}
ptestf() #调用自定义的test函数
tvar = $$prepf() #调用自定义的replace函数,replace函数调用必须在等号右边!
message($$var1) #输出1111
message($$var2) #输出2222
message($$var3) #输出3333
message($$var4) #输出空
message($$var5) #输出5555
函数内定义的变量作用于只在函数内有效。全局变量作用范围为从声明开始到整个工程解析结束,export(variable)出的全局变量variable作用范围从第一次调用函数开始。如下,第一次调用ttfun开始。
message($$tt1) #输出空
message($$tt2) #输出空
message($$tt3) #输出空
tt1=dae
defineTest(mytt){
message($$tt1)
message($$tt2)
message($$tt3)
}
tt2=ge
mytt() #输出dae
#输出ge
#输出空
tt3=eee
message($$tt1) #输出dae
message($$tt2) #输出ge
message($$tt3) #输出eee
defineTest(ttfun){
myvar.aa.cc=12345
myvar.aa.bb=$${LITERAL_HASH}define TT 12345 #$${LITERAL_HASH}表示qmake language中输出#号
export(myvar.aa.bb)
}
message($$myvar.aa.bb) #输出为空
ttfun()
message($$myvar.aa.cc) #输出空,全局环境中没有名字为myvar.aa.cc的变量
message($$myvar.aa.bb) #输出#define TT 12345,全局环境中有名字为myvar.aa.bb的变量且有值
qmake在源码端为qmake language定义的特殊变量: qmake language 关键字
函数定义和使用
1、函数定义的函数体或代码块必须用{}括起来,左括号“{”必须与函数名或者条件语句同行。如果不在同一行,必须要在后面加转义符号。
#defineReplace(repaceFunctionName){#defineReplace是关键字,表示定义replace函数。定义函数名字为repaceFunctionName的replace函数,函数的参数个数是不限制的,不需要列举参数名
defineReplace(repaceFunctionName)\
{
#.......#(函数体)函数体中语句结束不需要“;”!!!
}
defineTest(testFunctionName){defineTest是关键字,表示定义test函数。定义函数名字为testFunctionName的test函数。
#.......
}
2、函数返回值必须要用括号括起来。test函数如果需要返回值,最好显示的"return (true)"或"return (false)"。replace函数没有返回值则默认返回为空。
3、代码中区分test函数和replace函数的两种方法:
(1)看函数定义,如果是defineTest() defineReplace()分别是test函数和replace函数定义的标志
(2)replace函数使用时必须在前面加$$ 否则会被识别为test函数,如果不存在这样的test函数则会报错。
4、test函数的返回值无法赋予给变量,也无法打印出来,只能直接将test函数当做条件来使用。对于复杂的判断语句也只能直接将函数名进行拼接。
5、内置的replace 和test函数,传入函数参数时需要注意,有的函数需要传入变量名,有的函数需要传入变量的内容,需要视情况而定。比如greaterThan($$ARGC,1)和count(ARGS,2,>=)这两个test函数的传入参数。常用的打印函数message(), 如果想获取变量中的内容,须传入变量中的内容。
6、函数参数的个数在定义时无法通过模式进行限制。但是可以在函数体种通过加入判断语句进行筛查。因为qmake language只有字符串类型数据,所以传入的参数只有字符串类型。如果函数体没有用逻辑进行筛查,理论是可以传入无数个参数的。函数参数用逗号隔开。如果直接传入字符串其字符串中含有逗号,需要用双引号引起来,否则字符串会被当成多个参数。
7、函数内部的ARGC表示参数个数,ARGS表示参数列表,用空格隔开。size(ARGS)不一定等于ARGC,因为传入的参数很可能有含有空格的字符串。第一个参数存放在变量名为1的变量中,第二个存放在2中,依次类推。
案例:
defineTest(mytestFun){
message("argc=$${ARGC} , args=$${ARGS}")
count(ARGC,2){return (true)}
else{return (false)}
}
defineReplace(myreplaceFun){
count(ARGC,1,>=){message($$1)}
return ("$${ARGS} test")
}
build_pass{
mytestFun(1,2){message(here)}
else{message(gggg)}
}
mytestFun(aa,bb);
var=$$myreplaceFun(aa,bb)
message($$var)
输出:
Project MESSAGE: argc=2 , args=1 2
Project MESSAGE: gggg
Project MESSAGE: argc=2 , args=aa bb
Project MESSAGE: aa
Project MESSAGE: aa bb test
qmake language 内置函数 自定义函数 defineTest(testfunctionname) defineReplace(repacefunctionname)
快速查找qt pro文件中的用qmake language写的库函数_丘上人的博客-CSDN博客
判断语句和循环语句
判断语句的else和循环语句的for()后面的代码块如果没有{}括起来,必须要加冒号":",冒号的写法适合代码只有一行的代码块的简写。
判断语句
qmake中变量没有bool类型,也没有整数或浮点数的,只有字符串类型。qmake language中"true"和"false"都有两重意思,作为非判断语句的条件时,他们会被解析成字符串;作为判断语句的条件时,"true"和"false"才会被qmake做解释成C++bool类型,"true"会被解析成C++中的bool类型的true,"false"会被解析成C++中bool类型的false。"host_build"是与"true" "false"一样的关键字,也具有两重意思,区别在作为判断语句的条件时qmake根据配置情况将其解析成C++的bool类型的true或false。
判断语句
1、简单判断语句(样式:condition)
qmake language的condition可以是任何字符串。
(1)对于单独的字符串"true"会被解析成C++ bool类型的true
(2)对于单独的字符串"false"会被解析成C++bool的false
(3)对于单独的字符串"host_build"会根据情况解析成C++bool的true或false
(4)对于单独的字符串"build_pass"会在生成makefile的时候被解析成C++bool的true,其他时候被解析成C++bool的false
(5)对于CONFIG中存在的任何字符串,会被解析成C++bool的true:参考内建函数
(6)其他的任何字符串都会被解析成C++bool的false
(7)condition可以是test函数调用。根据函数返回解析成C++bool的true或false。test函数调用如果被双引号引用会被当做普通字符串。
var=aa
"false"{message(true)}
else:message(false)
"count(var,1)"{message(true)}
else:message(false)
#输出
#Project MESSAGE: false
#Project MESSAGE: false
2、非语句(样式:!condition),对条件进行取反运算。比如 !count(var,1)
2、或语句(样式:condition1|condition2),对两个条件进行或运算。
3、与语句(样式:condition1:condition2),对两个条件进行与运算。
4、与或非各种条件语句的组合,对多个条件进行运算。
5、条件conditions 不能直接用括号括起来,但是可以借助if(conditions)来达到目的。
条件分支
qmake language的判断语句 条件分支 分为then分支(没有then关键字)和else分支,分支必须用{}括起来,样式为:
conditions{
#then 分支内容
}
else{
#else分支内容
}
conditions:{} #不报错的冗余写法
else:{}
conditions{} #简化写法
else:单条语句
conditions:单条语句 #不报错的简化写法,但是不推荐,并且在某些条件语句组合下会出错!!!!
else:单条语句
conditions:单条语句 #错误写法,可能会导致出错
conditions{} #正确写法
if
if 在qmake language中是一个内置的test函数。样式为
if(conditions){
#then 分支
}
else{
#else 分支
}
案例
true{ #等价于if(true){ . if()是个test函数
#.....
}
else{
#......
}
!true{....}
var1=true
var2=false
$$var1|$$var2{ #表示var1或var2中的一个为true时执行{}中的内容
......
}
$$var1:$$var2{ #表示var1和var2都为true是执行{}中的内容
.....
}
isEmpty(PWD){
#.....
}else{
#......
}
#var=$$isEmpty(PWD) #函数返回值错误的使用方式 ,报错 #E:/workspace/QtWork/testEmpty/testEmpty.pro(24): 'isEmpty' is not a recognized replace function.
#这里描述了一种函数返回值的正确使用方式
var= #定义一个名字为var的空变量。下面的操作实现将test函数返回值赋予var
isEmpty(PWD){var=true}
else{var=false}
$$var{
#....
}else{
#......
}
!build_pass{ #build_pass特殊变量,该语句的意思在创建makefile时为true
var=
var1=isEmpty(var)
$$var1{message(empty)} #$$只能取一次值,取值为isEmpty(var)后不会继续执行isEmpty(var),isEmpty(var)不是关键字,所以这里判断语句是有问题的!!
else{message(not empty)}
var2=
isEmpty(var){var2=true}
else{var2=false}
$$var2{message(empty)}
else:message(not empty)
}
#输出:
#Project MESSAGE: not empty
#Project MESSAGE: empty
判断条件和else之后如果没有{},必须在其后加":"
true:message(1)
else:message(2)
循环语句
有三种:for(iterate,list) for(ever) for(var,forever)。结合break(),next(),return() 进行使用
for(iterate,list)
for(iterate,list)是一个特殊的内建test函数,它直到枚举完list的内容或遇到break或return才跳出循环体。
!build_pass:{ #build_pass特殊变量,该语句的意思表示只执行一遍。
var=11 22 33 44 55
for(t,var):message($$t)
message(end1)
for(t,var){
message($$t)
equals(t,33){
break()
}
}
message(end2)
for(t,var){
message($$t)
equals(t,33){
return()
}
}
message(end3)
}
message(end4)
#输出:
#Project MESSAGE: 11
#Project MESSAGE: 22
#Project MESSAGE: 33
#Project MESSAGE: 44
#Project MESSAGE: 55
#Project MESSAGE: end1
#Project MESSAGE: 11
#Project MESSAGE: 22
#Project MESSAGE: 33
#Project MESSAGE: end2
#Project MESSAGE: 11
#Project MESSAGE: 22
#Project MESSAGE: 33
#Project MESSAGE: end4
for(ever)
没有遇到break(),无限循环,循环次数最多执行1000次(qmake中代码中写死),否则会报错
build_pass{ #循环
var = 10
for(ever){
var=$$num_add($$var,-1) #减一操作
equals(var,5)|lessThan(var,5){break()} #当var<=5的时候退出
message(here$$var)
}
}
for(var,forever)
没有遇到break()\return()代码会无限循环,无限循环最高循环次数最多执行1000次(qmake中代码中写死),否则会报错。
传入的var作为内部存放计数器数值的变量,从0开始(原来的值会被qmake抹除,传入的var只是被当做一个计数器变量使用),运行一遍循环内容,计数器变量值就加1,并存入到变量中。循环内部修改var值无效!!!主要意义是将var作为传出参数查看执行次数。
build_pass{ #循环
var = 0
for(var,forever){ #传入的var作为内部存放数值的变量,运行一遍循环内容就加1。循环内部修改var值无效!!!主要意义是将var作为传出参数查看执行次数。
equals(var,5)|greaterThan(var,5){break()} #当var<=5的时候退出
message(here$$var)
}
}
break(),next(),return()
分别表示:退出for循环、结束本次循环执行下一次循环、退出函数。
build_pass{
for(var,forever){
lessThan(var,3){next()}
greaterThan(var,5){break()}
message($$var)
}
}
#Project MESSAGE: 3
#Project MESSAGE: 4
#Project MESSAGE: 5
for()之后如果没有{},for()后面必须加":"
list= 11 22 33 44
for(var,list):message($$var)
案例
defineTest(mytestFun){
message(argc=$${ARGC} args=$${ARGS}) #等价于message("argc=$${ARGC} args=$${ARGS}")
greaterThan($$ARGC,1){message(in greaterThan block:$$1)}
count(ARGS,2,>=){message(in count block:$$2)}
var=
message("in for(var,list) block")
for(var,ARGS):message($$var)
message("in for(var,forever) block")
for(var,forever){
!lessThan(var,$$ARGC){break()}
t=$$num_add($$var,1)
message($${t}:$${eval($$t)})
}
}
mytestFun(aa,bb,11,3rr)
输出:
Project MESSAGE: argc=4 args=aa bb 11 3rr
Project MESSAGE: in greaterThan block:aa
Project MESSAGE: in count block:bb
Project MESSAGE: in for(var,list) block
Project MESSAGE: aa
Project MESSAGE: bb
Project MESSAGE: 11
Project MESSAGE: 3rr
Project MESSAGE: in for(var,forever) block
Project MESSAGE: 1:aa
Project MESSAGE: 2:bb
Project MESSAGE: 3:11
Project MESSAGE: 4:3rr
qmake language相关的文件后缀
相关参考 qmake 与 配置文件
qmake language相关的文件后缀包括
.prf:project feature,用于存放全局定义的replace函数和test函数,以及达到目标设置而直接执行的代码逻辑。用于load()函数进行调用,可以加文件后缀名。load(feature[, ignore_errors=false])。也可以用include进行加载。对于比较庞大的工程,可以将自定义的replace函数和test函数放到自定义.prf文件,方便批处理,简化工程文件内容(就这一点功能,qt显得多次一举,明明makefile就能实现这样的功能,这样操作之后生成的makefile变得难以阅读了)。
.pri:project include,用于存放库信息及其依赖关系,包括名字、支持的功能特性(feature)、不支持的功能特性(feature),用include()函数进行调用,需要加后缀名。这里的feature是与qt模块的功能相关的,并且都有一个对应的.h文件,比如mkspecs/modules/qt_lib_widgets.pri,对应的qtwidget源码中的qtwidgets-config.h文件,每一个属性在.h中都有一个宏,用于控制代码逻辑,比如其中的dockwidget功能,可以通过修改对应的宏的值来达到禁用会启用对应的功能特性。QT_CONFIG
![](https://img-blog.csdnimg.cn/2747ebec8ea94656911afa365955588f.png)
![](https://img-blog.csdnimg.cn/0d1fd6e48e2b424884e3493c5066b633.png)
include(file [,into [,silent=false]])。qt为每个模块编写.pri文件,放置在mkspecs/modules中。
下面是qt_lib_core.pri的内容。qt模块对应的.pri文件的主要目的是方便在pro中对模块功能特性进行查询和确认。
#D:\Qt\Qt5.12.0\5.12.0\msvc2015_64\mkspecs\modules\qt_lib_core.pri
QT.core.VERSION = 5.12.0
QT.core.name = QtCore
QT.core.module = Qt5Core
QT.core.libs = $$QT_MODULE_LIB_BASE
QT.core.includes = $$QT_MODULE_INCLUDE_BASE $$QT_MODULE_INCLUDE_BASE/QtCore
QT.core.frameworks =
QT.core.bins = $$QT_MODULE_BIN_BASE
QT.core.depends =
QT.core.uses = libatomic
QT.core.module_config = v2
QT.core.CONFIG = moc resources
QT.core.DEFINES = QT_CORE_LIB
QT.core.enabled_features = properties animation textcodec big_codecs codecs commandlineparser cxx11_future textdate datestring filesystemiterator filesystemwatcher gestures itemmodel proxymodel identityproxymodel library mimetype processenvironment process statemachine qeventtransition regularexpression settings sharedmemory sortfilterproxymodel std-atomic64 stringlistmodel systemsemaphore temporaryfile timezone topleveldomain translation xmlstream xmlstreamreader xmlstreamwriter
QT.core.disabled_features =
QT_CONFIG += properties animation textcodec big_codecs codecs textdate datestring doubleconversion filesystemiterator filesystemwatcher gestures itemmodel proxymodel identityproxymodel library mimetype process statemachine regularexpression settings sharedmemory sortfilterproxymodel stringlistmodel systemsemaphore temporaryfile translation xmlstream xmlstreamreader xmlstreamwriter
QT_MODULES += core
qt每个模块都有一个对应的private模块。比如widgets对应会有一个widgets-private,他们的pri分别为qt_lib_widgets.pri和qt_lib-widgets_private.lib。qt 私有头文件 private
qt_configure.prf中存放了各种操作.pri内容的脚本函数,而该文件只在编译qt时会调用,用于生成库对应的pri文件。pri中的某个feature是否被支持,可以用脚本函数 qtConfig() 进行判断。pri中的feature相关的项主要用于在pro文件中进行查询,如果已经编译好的qt模块不支持要查询的特性,就可能需要重新配置和编译qt对应的模块。比如如果工程pro中的qtConfig(inputdialog)返回false,那么说明当前的工程不支持inputdialog特性。而inputdialog特性是在widgets模块中,如果工程中配置了widgets模块(QT+=widgets)而qtConfig(inputdialog)仍然返回false,就需要重新配置源码对应模块中的configure.json,然后编译Qt5WIdget.dll了。
qt模块feature QT_FEATURE_* qt_lib_*.pri QT_CONFG qtConfig
.prl:project library,用于描述该库的信息,包括编译该库的工程文件名*.pro、生成的lib的名字、版本、编译该库时配置的CONFIG值、依赖库等信息。该文件与.lib库文件一一对应的,方便用户在加载对应lib后,不需要额外对该lib所依赖的库再做操作,只需要将lib对应的prl放置在同一路径下即可,qmake会自动加载对应的prl文件,在调用lib的pro文件中配置CONFIG +=link_prl。qt为每个qt模块的lib编写对应的.prl文件,并与qt的模块的静态库“.lib”放置在同一个文件夹下。几个特殊的变量:QMAKE_PRL_TARGET、QMAKE_PRL_TARGET、QMAKE_PRL_DEFINES、QMAKE_PRL_CFLAGS、QMAKE_PRL_CXXFLAGS、QMAKE_PRL_CONFIG、QMAKE_PRL_LIBS、QMAKE_PRL_VERSION。
#D:\Qt\Qt5.12.0\5.12.0\msvc2015_64\lib\Qt5Core.prl
QMAKE_PRO_INPUT = corelib.pro
QMAKE_PRL_TARGET = Qt5Core.lib
QMAKE_PRL_CONFIG = lex yacc exceptions depend_includepath testcase_targets import_plugins import_qpa_plugin windows qt_build_extra file_copies qmake_use qt warn_on release link_prl flat debug_and_release precompile_header autogen_precompile_source embed_manifest_dll embed_manifest_exe shared release no_plugin_manifest win32 msvc copy_dir_files sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 compile_examples f16c force_debug_info largefile precompile_header rdrnd shani x86SimdAlways prefix_build force_independent utf8_source create_prl link_prl prepare_docs qt_docs_targets no_private_qt_headers_warning QTDIR_build qt_example_installs testcase_exceptions warning_clean release ReleaseBuild Release build_pass c++11 win32-msvc2015 exceptions qt_tracepoints moc resources simd optimize_full no_core_dep pcre2 generated_privates relative_qt_rpath git_build qmake_cache target_qt c++11 strict_c++ qt_install_headers need_fwd_pri qt_install_module debug_and_release build_all create_cmake skip_target_version_ext release ReleaseBuild Release build_pass have_target dll exclusive_builds debug_info no_autoqmake arch_haswell thread
QMAKE_PRL_VERSION = 5.12.0
可以为自己创建的库创建.prl文件,如下,plugin或static至少配置一个。当然也可以为第三方的lib或dll添加.prl文件。
TEMPLATE = lib
CONFIG += plugin static create_prl
.conf:configuration,用于存放系统相关的配置文件,用include()函数进行调用,需要加后缀名。
杂谈
for被解析成特殊的test函数,不能作condition用。
qmake 源码中对判断语句的处理逻辑,正确的处理方式都是走入isAcitiveConfig()中。也就是说判断语句如果不是true、false、host_build以及函数返回值,则会判断该单词是不是存在CONFIG中!由此可知debug、CONFIG(debug)、isActiveConfig(debug)三者做判断语句时是等价的。
//E:\workspace\QtWork\qmake\library\qmakeevaluator.cpp
QMakeEvaluator::VisitReturn QMakeEvaluator::visitProBlock(
const ushort *tokPtr)
{
.......
case TokCondition:
if (!m_skipLevel && okey != or_op) {
if (curr.size() != 1) {
if (!m_cumulative || !curr.isEmpty())
evalError(fL1S("Conditional must expand to exactly one word."));
okey = false;
} else {
okey = isActiveConfig(curr.at(0).toQStringRef(), true);
traceMsg("condition %s is %s", dbgStr(curr.at(0)), dbgBool(okey));
okey ^= invert;
}
} else {
traceMsg("skipped condition %s", curr.size() == 1 ? dbgStr(curr.at(0)) : "<invalid>");
}
or_op = !okey; // tentatively force next evaluation
invert = false;
curr.clear();
continue;
.......
}
--------------------
//E:\workspace\QtWork\qmake\library\qmakeevaluator.cpp
bool QMakeEvaluator::isActiveConfig(const QStringRef &config, bool regex)
{
// magic types for easy flipping
if (config == statics.strtrue)
return true;
if (config == statics.strfalse)
return false;
if (config == statics.strhost_build)
return m_hostBuild;
if (regex && (config.contains(QLatin1Char('*')) || config.contains(QLatin1Char('?')))) {
QRegExp re(config.toString(), Qt::CaseSensitive, QRegExp::Wildcard);
// mkspecs
if (re.exactMatch(m_qmakespecName))
return true;
// CONFIG variable
const auto configValues = values(statics.strCONFIG);
for (const ProString &configValue : configValues) {
ProStringRoUser u1(configValue, m_tmp[m_toggle ^= 1]);
if (re.exactMatch(u1.str()))
return true;
}
} else {
// mkspecs
if (m_qmakespecName == config)
return true;
// CONFIG variable
if (values(statics.strCONFIG).contains(config))
return true;
}
return false;
}
build_pass:qt 工程构建过程 默认构建路径设置 通过Dos窗口运行命令编译_丘上人的博客
Qt qmake - 看企鹅编程网
qmake对一个简单的pro文件(t.pro)的解析日志_丘上人的博客-CSDN博客