val_escape(varialblename)是qmake language中的内建函数,其目的是对variable的值(string类型)中无法单独显示的字符('\n' '\r' '\t')用qmake language语法的形式显示的进行替换。
qmake language对字符的转义是在词法分析阶段,转义字符包括: ,而对\n,\t,\r不会做转义。在pro文件向string中嵌入'\n' '\r' '\t'需要通过replace函数 escape_expand(string[,string[.....]])进行操作。
var = aaa\nbbb
message($$var)
message(\[ \] \{ \} \( \) \$ \\ \' \" aa\nbb\rcc\tdd)
var = aaa$$escape_expand(\n)bbb
message($$var)
#输出:
#Project MESSAGE: aaa\nbbb
#Project MESSAGE: [ ] { } ( ) $ \ ' " aa\nbb\rcc\tdd
#Project MESSAGE: aaa
#bbb
val_escape(variablename)则是对variable的value中的'\n' '\r' '\t' ‘#’ 转换成qmake language中合法的形式
var = aaa$$escape_expand(\n)bbb
message($$var)
var = $$val_escape(var)
message($$var)
#输出:
#Project MESSAGE: aaa
#bbb
#Project MESSAGE: aaa$$escape_expand(\\n)bbb
var=message($$var) #拼接出一个字符串。
message($$var)
eval($$var) #因为函数前面没有$$,此处的eval会被解析成test函数,其工作就是将传入的字符串作为qmak language的语句进行执行。
#输出:
#Project MESSAGE: message(aaa$$escape_expand(\\n)bbb)
#Project MESSAGE: aaa
#bbb
var=aa$$escape_expand(\n)bb$$escape_expand(\t)cc$$escape_expand(\r)dd$${LITERAL_HASH}ee #$${LITERAL_HASH}表示#
message($$var)
var = $$val_escape(var)
message($$var)
var=message($$var)
eval($$var)
#输出:
#Project MESSAGE: aa$$escape_expand(\\n)bb$$escape_expand(\\t)cc$$escape_expand(\\r)dd$${LITERAL_HASH}ee
#Project MESSAGE: aa
#bb cc
#dd#ee
下面是val_escape(variablename)的实现逻辑
//D:\Qt\Qt5.12.0\5.12.0\Src\qtbase\qmake\library\qmakebuiltins.cpp
QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand(
const QMakeBuiltin &adef, const ProKey &func, const ProStringList &args, ProStringList &ret)
{
......
case E_VAL_ESCAPE: {
const ProStringList &vals = values(args.at(0).toKey());
ret.reserve(vals.size());
for (const ProString &str : vals)
ret += ProString(quoteValue(str));
break;
}
.....
}
QString
QMakeEvaluator::quoteValue(const ProString &val)
{
QString ret;
ret.reserve(val.size());
const QChar *chars = val.constData();
bool quote = val.isEmpty();
bool escaping = false;
for (int i = 0, l = val.size(); i < l; i++) {
QChar c = chars[i];
ushort uc = c.unicode();
if (uc < 32) {
if (!escaping) {
escaping = true;
ret += QLatin1String("$$escape_expand(");
}
switch (uc) {
case '\r':
ret += QLatin1String("\\\\r");
break;
case '\n':
ret += QLatin1String("\\\\n");
break;
case '\t':
ret += QLatin1String("\\\\t");
break;
default:
ret += QString::fromLatin1("\\\\x%1").arg(uc, 2, 16, QLatin1Char('0'));
break;
}
} else {
if (escaping) {
escaping = false;
ret += QLatin1Char(')');
}
switch (uc) {
case '\\':
ret += QLatin1String("\\\\");
break;
case '"':
ret += QLatin1String("\\\"");
break;
case '\'':
ret += QLatin1String("\\'");
break;
case '$':
ret += QLatin1String("\\$");
break;
case '#':
ret += QLatin1String("$${LITERAL_HASH}");
break;
case 32:
quote = true;
Q_FALLTHROUGH();
default:
ret += c;
break;
}
}
}
if (escaping)
ret += QLatin1Char(')');
if (quote) {
ret.prepend(QLatin1Char('"'));
ret.append(QLatin1Char('"'));
}
return ret;
}