2009-02-25 09:15:00 +01:00
|
|
|
/**************************************************************************
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
|
|
|
|
** This file is part of Qt Creator
|
|
|
|
|
**
|
2012-01-26 18:33:46 +01:00
|
|
|
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2011-11-02 15:59:12 +01:00
|
|
|
** Contact: Nokia Corporation (qt-info@nokia.com)
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** GNU Lesser General Public License Usage
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2011-04-13 08:42:33 +02:00
|
|
|
** This file may be used under the terms of the GNU Lesser General Public
|
|
|
|
|
** License version 2.1 as published by the Free Software Foundation and
|
|
|
|
|
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
|
|
|
|
** Please review the following information to ensure the GNU Lesser General
|
|
|
|
|
** Public License version 2.1 requirements will be met:
|
|
|
|
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2010-12-17 16:01:08 +01:00
|
|
|
** In addition, as a special exception, Nokia gives you certain additional
|
2011-04-13 08:42:33 +02:00
|
|
|
** rights. These rights are described in the Nokia Qt LGPL Exception
|
2010-12-17 16:01:08 +01:00
|
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
|
**
|
2011-04-13 08:42:33 +02:00
|
|
|
** Other Usage
|
|
|
|
|
**
|
|
|
|
|
** Alternatively, this file may be used in accordance with the terms and
|
|
|
|
|
** conditions contained in a signed written agreement between you and Nokia.
|
|
|
|
|
**
|
2010-12-17 16:01:08 +01:00
|
|
|
** If you have questions regarding the use of this file, please contact
|
2011-11-02 15:59:12 +01:00
|
|
|
** Nokia at qt-info@nokia.com.
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
**************************************************************************/
|
2008-12-02 12:57:59 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
#include "profileevaluator.h"
|
2010-06-18 19:48:07 +02:00
|
|
|
|
2012-05-02 18:34:25 +02:00
|
|
|
#include "qmakeglobals.h"
|
2012-05-02 15:39:02 +02:00
|
|
|
#include "qmakeparser.h"
|
2012-05-02 18:59:46 +02:00
|
|
|
#include "qmakeevaluator.h"
|
2012-05-02 19:20:16 +02:00
|
|
|
#include "qmakeevaluator_p.h"
|
2010-01-22 12:26:14 +01:00
|
|
|
#include "ioutils.h"
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QByteArray>
|
|
|
|
|
#include <QDateTime>
|
|
|
|
|
#include <QDebug>
|
|
|
|
|
#include <QDir>
|
|
|
|
|
#include <QFile>
|
|
|
|
|
#include <QFileInfo>
|
|
|
|
|
#include <QList>
|
|
|
|
|
#include <QRegExp>
|
|
|
|
|
#include <QSet>
|
|
|
|
|
#include <QStack>
|
|
|
|
|
#include <QString>
|
|
|
|
|
#include <QStringList>
|
2010-06-18 19:48:07 +02:00
|
|
|
#ifdef PROEVALUATOR_THREAD_SAFE
|
2012-02-15 10:42:41 +01:00
|
|
|
# include <QThreadPool>
|
2010-02-26 12:53:30 +01:00
|
|
|
#endif
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2008-12-12 16:30:31 +01:00
|
|
|
#ifdef Q_OS_UNIX
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <sys/utsname.h>
|
2009-06-03 20:45:49 +02:00
|
|
|
#else
|
2008-12-12 16:30:31 +01:00
|
|
|
#include <Windows.h>
|
|
|
|
|
#endif
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
2010-01-22 12:26:14 +01:00
|
|
|
using namespace ProFileEvaluatorInternal;
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
using namespace ProStringConstants;
|
|
|
|
|
|
|
|
|
|
|
2011-03-18 20:03:22 +01:00
|
|
|
#define fL1S(s) QString::fromLatin1(s)
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
2012-05-02 15:43:12 +02:00
|
|
|
// QMakeEvaluator
|
2008-12-02 12:01:29 +01:00
|
|
|
//
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2012-05-02 19:20:16 +02:00
|
|
|
namespace ProFileEvaluatorInternal {
|
|
|
|
|
QMakeStatics statics;
|
|
|
|
|
}
|
2010-02-08 16:47:25 +01:00
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
void QMakeEvaluator::initStatics()
|
2010-02-08 16:47:25 +01:00
|
|
|
{
|
|
|
|
|
if (!statics.field_sep.isNull())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
statics.field_sep = QLatin1String(" ");
|
2010-02-08 17:15:44 +01:00
|
|
|
statics.strtrue = QLatin1String("true");
|
|
|
|
|
statics.strfalse = QLatin1String("false");
|
|
|
|
|
statics.strunix = QLatin1String("unix");
|
|
|
|
|
statics.strmacx = QLatin1String("macx");
|
|
|
|
|
statics.strmac = QLatin1String("mac");
|
|
|
|
|
statics.strwin32 = QLatin1String("win32");
|
2011-03-18 20:41:40 +01:00
|
|
|
statics.strsymbian = QLatin1String("symbian");
|
2010-04-27 18:39:10 +02:00
|
|
|
statics.strCONFIG = ProString("CONFIG");
|
|
|
|
|
statics.strARGS = ProString("ARGS");
|
2010-02-08 17:15:44 +01:00
|
|
|
statics.strDot = QLatin1String(".");
|
|
|
|
|
statics.strDotDot = QLatin1String("..");
|
|
|
|
|
statics.strever = QLatin1String("ever");
|
|
|
|
|
statics.strforever = QLatin1String("forever");
|
2010-04-27 18:39:10 +02:00
|
|
|
statics.strTEMPLATE = ProString("TEMPLATE");
|
|
|
|
|
statics.strQMAKE_DIR_SEP = ProString("QMAKE_DIR_SEP");
|
2010-02-08 17:15:44 +01:00
|
|
|
|
|
|
|
|
statics.reg_variableName.setPattern(QLatin1String("\\$\\(.*\\)"));
|
|
|
|
|
statics.reg_variableName.setMinimal(true);
|
2010-02-08 16:47:25 +01:00
|
|
|
|
2012-07-03 12:18:47 +02:00
|
|
|
statics.fakeValue = ProStringList(ProString("_FAKE_")); // It has to have a unique begin() value
|
2010-02-09 20:38:21 +01:00
|
|
|
|
2012-05-02 19:20:16 +02:00
|
|
|
initFunctionStatics();
|
2010-02-08 16:47:25 +01:00
|
|
|
|
|
|
|
|
static const char * const names[] = {
|
|
|
|
|
"LITERAL_DOLLAR", "LITERAL_HASH", "LITERAL_WHITESPACE",
|
|
|
|
|
"DIRLIST_SEPARATOR", "DIR_SEPARATOR",
|
|
|
|
|
"OUT_PWD", "PWD", "IN_PWD",
|
|
|
|
|
"_FILE_", "_LINE_", "_PRO_FILE_", "_PRO_FILE_PWD_",
|
|
|
|
|
"QMAKE_HOST.arch", "QMAKE_HOST.name", "QMAKE_HOST.os",
|
|
|
|
|
"QMAKE_HOST.version", "QMAKE_HOST.version_string",
|
|
|
|
|
"_DATE_", "_QMAKE_CACHE_"
|
|
|
|
|
};
|
|
|
|
|
for (unsigned i = 0; i < sizeof(names)/sizeof(names[0]); ++i)
|
2010-04-27 18:39:10 +02:00
|
|
|
statics.varList.insert(ProString(names[i]), i);
|
2010-02-11 16:33:16 +01:00
|
|
|
|
|
|
|
|
static const struct {
|
|
|
|
|
const char * const oldname, * const newname;
|
|
|
|
|
} mapInits[] = {
|
|
|
|
|
{ "INTERFACES", "FORMS" },
|
|
|
|
|
{ "QMAKE_POST_BUILD", "QMAKE_POST_LINK" },
|
|
|
|
|
{ "TARGETDEPS", "POST_TARGETDEPS" },
|
|
|
|
|
{ "LIBPATH", "QMAKE_LIBDIR" },
|
|
|
|
|
{ "QMAKE_EXT_MOC", "QMAKE_EXT_CPP_MOC" },
|
|
|
|
|
{ "QMAKE_MOD_MOC", "QMAKE_H_MOD_MOC" },
|
|
|
|
|
{ "QMAKE_LFLAGS_SHAPP", "QMAKE_LFLAGS_APP" },
|
|
|
|
|
{ "PRECOMPH", "PRECOMPILED_HEADER" },
|
|
|
|
|
{ "PRECOMPCPP", "PRECOMPILED_SOURCE" },
|
|
|
|
|
{ "INCPATH", "INCLUDEPATH" },
|
|
|
|
|
{ "QMAKE_EXTRA_WIN_COMPILERS", "QMAKE_EXTRA_COMPILERS" },
|
|
|
|
|
{ "QMAKE_EXTRA_UNIX_COMPILERS", "QMAKE_EXTRA_COMPILERS" },
|
|
|
|
|
{ "QMAKE_EXTRA_WIN_TARGETS", "QMAKE_EXTRA_TARGETS" },
|
|
|
|
|
{ "QMAKE_EXTRA_UNIX_TARGETS", "QMAKE_EXTRA_TARGETS" },
|
|
|
|
|
{ "QMAKE_EXTRA_UNIX_INCLUDES", "QMAKE_EXTRA_INCLUDES" },
|
|
|
|
|
{ "QMAKE_EXTRA_UNIX_VARIABLES", "QMAKE_EXTRA_VARIABLES" },
|
|
|
|
|
{ "QMAKE_RPATH", "QMAKE_LFLAGS_RPATH" },
|
|
|
|
|
{ "QMAKE_FRAMEWORKDIR", "QMAKE_FRAMEWORKPATH" },
|
|
|
|
|
{ "QMAKE_FRAMEWORKDIR_FLAGS", "QMAKE_FRAMEWORKPATH_FLAGS" }
|
|
|
|
|
};
|
|
|
|
|
for (unsigned i = 0; i < sizeof(mapInits)/sizeof(mapInits[0]); ++i)
|
2010-04-27 18:39:10 +02:00
|
|
|
statics.varMap.insert(ProString(mapInits[i].oldname),
|
|
|
|
|
ProString(mapInits[i].newname));
|
2010-02-11 16:33:16 +01:00
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
const ProString &QMakeEvaluator::map(const ProString &var)
|
2010-02-11 16:33:16 +01:00
|
|
|
{
|
2010-06-23 19:32:57 +02:00
|
|
|
QHash<ProString, ProString>::ConstIterator it = statics.varMap.constFind(var);
|
|
|
|
|
return (it != statics.varMap.constEnd()) ? it.value() : var;
|
2010-02-08 16:47:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
QMakeEvaluator::QMakeEvaluator(QMakeGlobals *option,
|
|
|
|
|
QMakeParser *parser, QMakeEvaluatorHandler *handler)
|
2012-05-02 14:58:24 +02:00
|
|
|
: m_option(option), m_parser(parser), m_handler(handler)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-02-08 16:47:25 +01:00
|
|
|
// So that single-threaded apps don't have to call initialize() for now.
|
|
|
|
|
initStatics();
|
|
|
|
|
|
2009-04-02 19:38:19 +02:00
|
|
|
// Configuration, more or less
|
2011-05-31 19:19:34 +02:00
|
|
|
#ifdef PROEVALUATOR_CUMULATIVE
|
2008-12-12 18:10:42 +01:00
|
|
|
m_cumulative = true;
|
2011-05-31 19:19:34 +02:00
|
|
|
#endif
|
2009-04-02 19:38:19 +02:00
|
|
|
|
|
|
|
|
// Evaluator state
|
2008-12-12 18:10:42 +01:00
|
|
|
m_skipLevel = 0;
|
2010-04-19 22:35:58 +02:00
|
|
|
m_loopLevel = 0;
|
2010-02-08 16:51:50 +01:00
|
|
|
m_listCount = 0;
|
2010-04-27 18:39:10 +02:00
|
|
|
m_valuemapStack.push(QHash<ProString, ProStringList>());
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
QMakeEvaluator::~QMakeEvaluator()
|
2009-08-10 17:27:07 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-23 16:34:30 +02:00
|
|
|
//////// Evaluator tools /////////
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
uint QMakeEvaluator::getBlockLen(const ushort *&tokPtr)
|
2010-05-11 12:24:05 +02:00
|
|
|
{
|
|
|
|
|
uint len = *tokPtr++;
|
|
|
|
|
len |= (uint)*tokPtr++ << 16;
|
|
|
|
|
return len;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
ProString QMakeEvaluator::getStr(const ushort *&tokPtr)
|
2010-05-11 12:24:05 +02:00
|
|
|
{
|
|
|
|
|
uint len = *tokPtr++;
|
2010-06-23 14:51:43 +02:00
|
|
|
ProString ret(m_current.pro->items(), tokPtr - m_current.pro->tokPtr(), len, NoHash);
|
2011-04-20 18:19:33 +02:00
|
|
|
ret.setSource(m_current.pro);
|
2010-05-11 12:24:05 +02:00
|
|
|
tokPtr += len;
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
ProString QMakeEvaluator::getHashStr(const ushort *&tokPtr)
|
2010-05-11 12:24:05 +02:00
|
|
|
{
|
|
|
|
|
uint hash = getBlockLen(tokPtr);
|
|
|
|
|
uint len = *tokPtr++;
|
2010-06-23 14:51:43 +02:00
|
|
|
ProString ret(m_current.pro->items(), tokPtr - m_current.pro->tokPtr(), len, hash);
|
2010-05-11 12:24:05 +02:00
|
|
|
tokPtr += len;
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
void QMakeEvaluator::skipStr(const ushort *&tokPtr)
|
2010-05-11 12:24:05 +02:00
|
|
|
{
|
|
|
|
|
uint len = *tokPtr++;
|
|
|
|
|
tokPtr += len;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
void QMakeEvaluator::skipHashStr(const ushort *&tokPtr)
|
2010-05-11 12:24:05 +02:00
|
|
|
{
|
|
|
|
|
tokPtr += 2;
|
|
|
|
|
uint len = *tokPtr++;
|
|
|
|
|
tokPtr += len;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
// FIXME: this should not build new strings for direct sections.
|
|
|
|
|
// Note that the E_SPRINTF and E_LIST implementations rely on the deep copy.
|
2012-05-02 15:43:12 +02:00
|
|
|
ProStringList QMakeEvaluator::split_value_list(const QString &vals, const ProFile *source)
|
2009-07-23 16:34:30 +02:00
|
|
|
{
|
|
|
|
|
QString build;
|
2010-04-27 18:39:10 +02:00
|
|
|
ProStringList ret;
|
2009-07-23 16:34:30 +02:00
|
|
|
QStack<char> quote;
|
|
|
|
|
|
2009-07-23 18:36:59 +02:00
|
|
|
const ushort SPACE = ' ';
|
2009-07-23 16:34:30 +02:00
|
|
|
const ushort LPAREN = '(';
|
|
|
|
|
const ushort RPAREN = ')';
|
|
|
|
|
const ushort SINGLEQUOTE = '\'';
|
|
|
|
|
const ushort DOUBLEQUOTE = '"';
|
|
|
|
|
const ushort BACKSLASH = '\\';
|
|
|
|
|
|
2011-05-13 20:20:41 +02:00
|
|
|
if (!source)
|
|
|
|
|
source = currentProFile();
|
|
|
|
|
|
2009-07-23 16:34:30 +02:00
|
|
|
ushort unicode;
|
|
|
|
|
const QChar *vals_data = vals.data();
|
|
|
|
|
const int vals_len = vals.length();
|
|
|
|
|
for (int x = 0, parens = 0; x < vals_len; x++) {
|
|
|
|
|
unicode = vals_data[x].unicode();
|
|
|
|
|
if (x != (int)vals_len-1 && unicode == BACKSLASH &&
|
|
|
|
|
(vals_data[x+1].unicode() == SINGLEQUOTE || vals_data[x+1].unicode() == DOUBLEQUOTE)) {
|
|
|
|
|
build += vals_data[x++]; //get that 'escape'
|
|
|
|
|
} else if (!quote.isEmpty() && unicode == quote.top()) {
|
|
|
|
|
quote.pop();
|
|
|
|
|
} else if (unicode == SINGLEQUOTE || unicode == DOUBLEQUOTE) {
|
|
|
|
|
quote.push(unicode);
|
|
|
|
|
} else if (unicode == RPAREN) {
|
|
|
|
|
--parens;
|
|
|
|
|
} else if (unicode == LPAREN) {
|
|
|
|
|
++parens;
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-14 17:43:02 +01:00
|
|
|
if (!parens && quote.isEmpty() && vals_data[x] == SPACE) {
|
2011-05-13 20:20:41 +02:00
|
|
|
ret << ProString(build, NoHash).setSource(source);
|
2009-07-23 16:34:30 +02:00
|
|
|
build.clear();
|
|
|
|
|
} else {
|
|
|
|
|
build += vals_data[x];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!build.isEmpty())
|
2011-05-13 20:20:41 +02:00
|
|
|
ret << ProString(build, NoHash).setSource(source);
|
2009-07-23 16:34:30 +02:00
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-27 20:21:01 +02:00
|
|
|
static void zipEmpty(ProStringList *value)
|
|
|
|
|
{
|
|
|
|
|
for (int i = value->size(); --i >= 0;)
|
|
|
|
|
if (value->at(i).isEmpty())
|
|
|
|
|
value->remove(i);
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
static void insertUnique(ProStringList *varlist, const ProStringList &value)
|
2009-07-23 16:34:30 +02:00
|
|
|
{
|
2010-04-27 18:39:10 +02:00
|
|
|
foreach (const ProString &str, value)
|
2010-05-27 20:21:01 +02:00
|
|
|
if (!str.isEmpty() && !varlist->contains(str))
|
2010-02-09 15:44:17 +01:00
|
|
|
varlist->append(str);
|
2009-07-23 16:34:30 +02:00
|
|
|
}
|
|
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
static void removeAll(ProStringList *varlist, const ProString &value)
|
2009-07-23 16:34:30 +02:00
|
|
|
{
|
2010-04-27 18:39:10 +02:00
|
|
|
for (int i = varlist->size(); --i >= 0; )
|
|
|
|
|
if (varlist->at(i) == value)
|
|
|
|
|
varlist->remove(i);
|
2009-07-23 16:34:30 +02:00
|
|
|
}
|
|
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
static void removeEach(ProStringList *varlist, const ProStringList &value)
|
2009-07-23 16:34:30 +02:00
|
|
|
{
|
2010-04-27 18:39:10 +02:00
|
|
|
foreach (const ProString &str, value)
|
2010-05-27 20:21:01 +02:00
|
|
|
if (!str.isEmpty())
|
|
|
|
|
removeAll(varlist, str);
|
2010-04-27 18:39:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void replaceInList(ProStringList *varlist,
|
|
|
|
|
const QRegExp ®exp, const QString &replace, bool global, QString &tmp)
|
|
|
|
|
{
|
|
|
|
|
for (ProStringList::Iterator varit = varlist->begin(); varit != varlist->end(); ) {
|
|
|
|
|
QString val = varit->toQString(tmp);
|
|
|
|
|
QString copy = val; // Force detach and have a reference value
|
|
|
|
|
val.replace(regexp, replace);
|
|
|
|
|
if (!val.isSharedWith(copy)) {
|
|
|
|
|
if (val.isEmpty()) {
|
2009-07-23 16:34:30 +02:00
|
|
|
varit = varlist->erase(varit);
|
2010-04-27 18:39:10 +02:00
|
|
|
} else {
|
2011-05-13 20:20:41 +02:00
|
|
|
(*varit).setValue(val, NoHash);
|
2009-07-23 16:34:30 +02:00
|
|
|
++varit;
|
2010-04-27 18:39:10 +02:00
|
|
|
}
|
2009-07-23 16:34:30 +02:00
|
|
|
if (!global)
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
++varit;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
QString QMakeEvaluator::expandEnvVars(const QString &str) const
|
2009-07-23 17:04:50 +02:00
|
|
|
{
|
|
|
|
|
QString string = str;
|
|
|
|
|
int rep;
|
2010-02-08 17:15:44 +01:00
|
|
|
QRegExp reg_variableName = statics.reg_variableName; // Copy for thread safety
|
2009-07-23 17:04:50 +02:00
|
|
|
while ((rep = reg_variableName.indexIn(string)) != -1)
|
|
|
|
|
string.replace(rep, reg_variableName.matchedLength(),
|
2011-04-20 21:16:17 +02:00
|
|
|
m_option->getEnv(string.mid(rep + 2, reg_variableName.matchedLength() - 3)));
|
2009-07-23 17:04:50 +02:00
|
|
|
return string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This is braindead, but we want qmake compat
|
2012-05-02 15:43:12 +02:00
|
|
|
QString QMakeEvaluator::fixPathToLocalOS(const QString &str) const
|
2009-07-23 17:04:50 +02:00
|
|
|
{
|
2010-02-11 12:42:40 +01:00
|
|
|
QString string = expandEnvVars(str);
|
2009-07-23 17:04:50 +02:00
|
|
|
|
2009-08-04 20:51:49 +02:00
|
|
|
if (string.length() > 2 && string.at(0).isLetter() && string.at(1) == QLatin1Char(':'))
|
2009-07-23 17:04:50 +02:00
|
|
|
string[0] = string[0].toLower();
|
|
|
|
|
|
|
|
|
|
#if defined(Q_OS_WIN32)
|
|
|
|
|
string.replace(QLatin1Char('/'), QLatin1Char('\\'));
|
|
|
|
|
#else
|
|
|
|
|
string.replace(QLatin1Char('\\'), QLatin1Char('/'));
|
|
|
|
|
#endif
|
|
|
|
|
return string;
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-23 16:34:30 +02:00
|
|
|
//////// Evaluator /////////
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-06-01 18:43:11 +02:00
|
|
|
static ALWAYS_INLINE void addStr(
|
|
|
|
|
const ProString &str, ProStringList *ret, bool &pending, bool joined)
|
|
|
|
|
{
|
|
|
|
|
if (joined) {
|
|
|
|
|
ret->last().append(str, &pending);
|
|
|
|
|
} else {
|
|
|
|
|
if (!pending) {
|
|
|
|
|
pending = true;
|
|
|
|
|
*ret << str;
|
|
|
|
|
} else {
|
|
|
|
|
ret->last().append(str);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static ALWAYS_INLINE void addStrList(
|
|
|
|
|
const ProStringList &list, ushort tok, ProStringList *ret, bool &pending, bool joined)
|
|
|
|
|
{
|
|
|
|
|
if (!list.isEmpty()) {
|
|
|
|
|
if (joined) {
|
|
|
|
|
ret->last().append(list, &pending, !(tok & TokQuoted));
|
|
|
|
|
} else {
|
|
|
|
|
if (tok & TokQuoted) {
|
|
|
|
|
if (!pending) {
|
|
|
|
|
pending = true;
|
|
|
|
|
*ret << ProString();
|
|
|
|
|
}
|
|
|
|
|
ret->last().append(list);
|
|
|
|
|
} else {
|
|
|
|
|
if (!pending) {
|
|
|
|
|
// Another qmake bizzarity: if nothing is pending and the
|
|
|
|
|
// first element is empty, it will be eaten
|
|
|
|
|
if (!list.at(0).isEmpty()) {
|
|
|
|
|
// The common case
|
2010-06-24 14:49:35 +02:00
|
|
|
pending = true;
|
2010-06-01 18:43:11 +02:00
|
|
|
*ret += list;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
ret->last().append(list.at(0));
|
|
|
|
|
}
|
|
|
|
|
// This is somewhat slow, but a corner case
|
2010-06-24 14:49:35 +02:00
|
|
|
for (int j = 1; j < list.size(); ++j) {
|
|
|
|
|
pending = true;
|
2010-06-01 18:43:11 +02:00
|
|
|
*ret << list.at(j);
|
2010-06-24 14:49:35 +02:00
|
|
|
}
|
2010-06-01 18:43:11 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
void QMakeEvaluator::evaluateExpression(
|
2010-06-01 18:43:11 +02:00
|
|
|
const ushort *&tokPtr, ProStringList *ret, bool joined)
|
|
|
|
|
{
|
|
|
|
|
if (joined)
|
|
|
|
|
*ret << ProString();
|
|
|
|
|
bool pending = false;
|
|
|
|
|
forever {
|
|
|
|
|
ushort tok = *tokPtr++;
|
|
|
|
|
if (tok & TokNewStr)
|
|
|
|
|
pending = false;
|
|
|
|
|
ushort maskedTok = tok & TokMask;
|
|
|
|
|
switch (maskedTok) {
|
|
|
|
|
case TokLine:
|
2010-06-23 13:58:44 +02:00
|
|
|
m_current.line = *tokPtr++;
|
2010-06-01 18:43:11 +02:00
|
|
|
break;
|
|
|
|
|
case TokLiteral:
|
|
|
|
|
addStr(getStr(tokPtr), ret, pending, joined);
|
|
|
|
|
break;
|
|
|
|
|
case TokHashLiteral:
|
|
|
|
|
addStr(getHashStr(tokPtr), ret, pending, joined);
|
|
|
|
|
break;
|
|
|
|
|
case TokVariable:
|
|
|
|
|
addStrList(values(map(getHashStr(tokPtr))), tok, ret, pending, joined);
|
|
|
|
|
break;
|
|
|
|
|
case TokProperty:
|
|
|
|
|
addStr(ProString(propertyValue(
|
2011-05-13 20:20:41 +02:00
|
|
|
getStr(tokPtr).toQString(m_tmp1), true), NoHash).setSource(currentProFile()),
|
|
|
|
|
ret, pending, joined);
|
2010-06-01 18:43:11 +02:00
|
|
|
break;
|
|
|
|
|
case TokEnvVar:
|
2011-04-20 21:16:17 +02:00
|
|
|
addStrList(split_value_list(m_option->getEnv(getStr(tokPtr).toQString(m_tmp1))),
|
|
|
|
|
tok, ret, pending, joined);
|
2010-06-01 18:43:11 +02:00
|
|
|
break;
|
|
|
|
|
case TokFuncName: {
|
|
|
|
|
ProString func = getHashStr(tokPtr);
|
|
|
|
|
addStrList(evaluateExpandFunction(func, tokPtr), tok, ret, pending, joined);
|
|
|
|
|
break; }
|
|
|
|
|
default:
|
|
|
|
|
tokPtr--;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
void QMakeEvaluator::skipExpression(const ushort *&pTokPtr)
|
2010-06-01 18:43:11 +02:00
|
|
|
{
|
|
|
|
|
const ushort *tokPtr = pTokPtr;
|
|
|
|
|
forever {
|
|
|
|
|
ushort tok = *tokPtr++;
|
|
|
|
|
switch (tok) {
|
|
|
|
|
case TokLine:
|
2010-06-23 13:58:44 +02:00
|
|
|
m_current.line = *tokPtr++;
|
2010-06-01 18:43:11 +02:00
|
|
|
break;
|
|
|
|
|
case TokValueTerminator:
|
|
|
|
|
case TokFuncTerminator:
|
|
|
|
|
pTokPtr = tokPtr;
|
|
|
|
|
return;
|
|
|
|
|
case TokArgSeparator:
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
switch (tok & TokMask) {
|
|
|
|
|
case TokLiteral:
|
|
|
|
|
case TokProperty:
|
|
|
|
|
case TokEnvVar:
|
|
|
|
|
skipStr(tokPtr);
|
|
|
|
|
break;
|
|
|
|
|
case TokHashLiteral:
|
|
|
|
|
case TokVariable:
|
|
|
|
|
skipHashStr(tokPtr);
|
|
|
|
|
break;
|
|
|
|
|
case TokFuncName:
|
|
|
|
|
skipHashStr(tokPtr);
|
|
|
|
|
pTokPtr = tokPtr;
|
|
|
|
|
skipExpression(pTokPtr);
|
|
|
|
|
tokPtr = pTokPtr;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
Q_ASSERT_X(false, "skipExpression", "Unrecognized token");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
QMakeEvaluator::VisitReturn QMakeEvaluator::visitProBlock(
|
2010-06-23 13:58:44 +02:00
|
|
|
ProFile *pro, const ushort *tokPtr)
|
|
|
|
|
{
|
|
|
|
|
m_current.pro = pro;
|
|
|
|
|
m_current.line = 0;
|
|
|
|
|
return visitProBlock(tokPtr);
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
QMakeEvaluator::VisitReturn QMakeEvaluator::visitProBlock(
|
2010-05-11 12:24:05 +02:00
|
|
|
const ushort *tokPtr)
|
2010-02-02 21:00:09 +01:00
|
|
|
{
|
2010-06-01 18:43:11 +02:00
|
|
|
ProStringList curr;
|
2010-04-19 22:35:58 +02:00
|
|
|
bool okey = true, or_op = false, invert = false;
|
2010-05-11 12:24:05 +02:00
|
|
|
uint blockLen;
|
2010-04-29 21:43:41 +02:00
|
|
|
VisitReturn ret = ReturnTrue;
|
2010-05-11 12:24:05 +02:00
|
|
|
while (ushort tok = *tokPtr++) {
|
|
|
|
|
switch (tok) {
|
|
|
|
|
case TokLine:
|
2010-06-23 13:58:44 +02:00
|
|
|
m_current.line = *tokPtr++;
|
2010-04-19 22:35:58 +02:00
|
|
|
continue;
|
2010-05-11 12:24:05 +02:00
|
|
|
case TokAssign:
|
|
|
|
|
case TokAppend:
|
|
|
|
|
case TokAppendUnique:
|
|
|
|
|
case TokRemove:
|
2010-06-01 18:43:11 +02:00
|
|
|
case TokReplace:
|
|
|
|
|
visitProVariable(tok, curr, tokPtr);
|
|
|
|
|
curr.clear();
|
|
|
|
|
continue;
|
2010-05-11 12:24:05 +02:00
|
|
|
case TokBranch:
|
|
|
|
|
blockLen = getBlockLen(tokPtr);
|
2010-04-19 22:35:58 +02:00
|
|
|
if (m_cumulative) {
|
|
|
|
|
if (!okey)
|
|
|
|
|
m_skipLevel++;
|
2010-05-11 12:24:05 +02:00
|
|
|
ret = blockLen ? visitProBlock(tokPtr) : ReturnTrue;
|
|
|
|
|
tokPtr += blockLen;
|
|
|
|
|
blockLen = getBlockLen(tokPtr);
|
2010-04-19 22:35:58 +02:00
|
|
|
if (!okey)
|
|
|
|
|
m_skipLevel--;
|
|
|
|
|
else
|
|
|
|
|
m_skipLevel++;
|
2010-05-11 12:24:05 +02:00
|
|
|
if ((ret == ReturnTrue || ret == ReturnFalse) && blockLen)
|
|
|
|
|
ret = visitProBlock(tokPtr);
|
2010-04-19 22:35:58 +02:00
|
|
|
if (okey)
|
|
|
|
|
m_skipLevel--;
|
|
|
|
|
} else {
|
2010-05-11 12:24:05 +02:00
|
|
|
if (okey)
|
|
|
|
|
ret = blockLen ? visitProBlock(tokPtr) : ReturnTrue;
|
|
|
|
|
tokPtr += blockLen;
|
|
|
|
|
blockLen = getBlockLen(tokPtr);
|
|
|
|
|
if (!okey)
|
|
|
|
|
ret = blockLen ? visitProBlock(tokPtr) : ReturnTrue;
|
2010-04-19 22:35:58 +02:00
|
|
|
}
|
2010-05-11 12:24:05 +02:00
|
|
|
tokPtr += blockLen;
|
2010-04-19 22:35:58 +02:00
|
|
|
okey = true, or_op = false; // force next evaluation
|
|
|
|
|
break;
|
2010-05-11 12:24:05 +02:00
|
|
|
case TokForLoop:
|
|
|
|
|
if (m_cumulative) { // This is a no-win situation, so just pretend it's no loop
|
|
|
|
|
skipHashStr(tokPtr);
|
2010-06-01 18:43:11 +02:00
|
|
|
uint exprLen = getBlockLen(tokPtr);
|
|
|
|
|
tokPtr += exprLen;
|
2010-05-11 12:24:05 +02:00
|
|
|
blockLen = getBlockLen(tokPtr);
|
|
|
|
|
ret = visitProBlock(tokPtr);
|
|
|
|
|
} else if (okey != or_op) {
|
|
|
|
|
const ProString &variable = getHashStr(tokPtr);
|
2010-06-01 18:43:11 +02:00
|
|
|
uint exprLen = getBlockLen(tokPtr);
|
|
|
|
|
const ushort *exprPtr = tokPtr;
|
|
|
|
|
tokPtr += exprLen;
|
2010-05-11 12:24:05 +02:00
|
|
|
blockLen = getBlockLen(tokPtr);
|
2010-06-01 18:43:11 +02:00
|
|
|
ret = visitProLoop(variable, exprPtr, tokPtr);
|
2010-05-11 12:24:05 +02:00
|
|
|
} else {
|
|
|
|
|
skipHashStr(tokPtr);
|
2010-06-01 18:43:11 +02:00
|
|
|
uint exprLen = getBlockLen(tokPtr);
|
|
|
|
|
tokPtr += exprLen;
|
2010-05-11 12:24:05 +02:00
|
|
|
blockLen = getBlockLen(tokPtr);
|
|
|
|
|
ret = ReturnTrue;
|
|
|
|
|
}
|
|
|
|
|
tokPtr += blockLen;
|
2010-04-19 22:35:58 +02:00
|
|
|
okey = true, or_op = false; // force next evaluation
|
|
|
|
|
break;
|
2010-05-11 12:24:05 +02:00
|
|
|
case TokTestDef:
|
|
|
|
|
case TokReplaceDef:
|
|
|
|
|
if (m_cumulative || okey != or_op) {
|
|
|
|
|
const ProString &name = getHashStr(tokPtr);
|
|
|
|
|
blockLen = getBlockLen(tokPtr);
|
|
|
|
|
visitProFunctionDef(tok, name, tokPtr);
|
|
|
|
|
} else {
|
|
|
|
|
skipHashStr(tokPtr);
|
|
|
|
|
blockLen = getBlockLen(tokPtr);
|
|
|
|
|
}
|
|
|
|
|
tokPtr += blockLen;
|
2010-04-19 22:35:58 +02:00
|
|
|
okey = true, or_op = false; // force next evaluation
|
|
|
|
|
continue;
|
2010-05-11 12:24:05 +02:00
|
|
|
case TokNot:
|
2010-04-19 22:35:58 +02:00
|
|
|
invert ^= true;
|
2010-05-11 12:24:05 +02:00
|
|
|
continue;
|
|
|
|
|
case TokAnd:
|
2010-04-19 22:35:58 +02:00
|
|
|
or_op = false;
|
2010-05-11 12:24:05 +02:00
|
|
|
continue;
|
|
|
|
|
case TokOr:
|
2010-04-19 22:35:58 +02:00
|
|
|
or_op = true;
|
2010-05-11 12:24:05 +02:00
|
|
|
continue;
|
|
|
|
|
case TokCondition:
|
2010-04-19 22:35:58 +02:00
|
|
|
if (!m_skipLevel && okey != or_op) {
|
2010-06-01 18:43:11 +02:00
|
|
|
if (curr.size() != 1) {
|
2011-04-06 21:26:20 +02:00
|
|
|
if (!m_cumulative || !curr.isEmpty())
|
|
|
|
|
evalError(fL1S("Conditional must expand to exactly one word."));
|
2010-06-01 18:43:11 +02:00
|
|
|
okey = false;
|
|
|
|
|
} else {
|
|
|
|
|
okey = isActiveConfig(curr.at(0).toQString(m_tmp2), true) ^ invert;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
or_op = !okey; // tentatively force next evaluation
|
|
|
|
|
invert = false;
|
|
|
|
|
curr.clear();
|
|
|
|
|
continue;
|
|
|
|
|
case TokTestCall:
|
|
|
|
|
if (!m_skipLevel && okey != or_op) {
|
|
|
|
|
if (curr.size() != 1) {
|
2011-04-06 21:26:20 +02:00
|
|
|
if (!m_cumulative || !curr.isEmpty())
|
|
|
|
|
evalError(fL1S("Test name must expand to exactly one word."));
|
2010-06-01 18:43:11 +02:00
|
|
|
skipExpression(tokPtr);
|
|
|
|
|
okey = false;
|
|
|
|
|
} else {
|
|
|
|
|
ret = evaluateConditionalFunction(curr.at(0), tokPtr);
|
|
|
|
|
switch (ret) {
|
|
|
|
|
case ReturnTrue: okey = true; break;
|
|
|
|
|
case ReturnFalse: okey = false; break;
|
|
|
|
|
default: return ret;
|
|
|
|
|
}
|
|
|
|
|
okey ^= invert;
|
2010-04-19 22:35:58 +02:00
|
|
|
}
|
|
|
|
|
} else if (m_cumulative) {
|
|
|
|
|
m_skipLevel++;
|
2010-06-01 18:43:11 +02:00
|
|
|
if (curr.size() != 1)
|
|
|
|
|
skipExpression(tokPtr);
|
|
|
|
|
else
|
|
|
|
|
evaluateConditionalFunction(curr.at(0), tokPtr);
|
2010-04-19 22:35:58 +02:00
|
|
|
m_skipLevel--;
|
2010-05-11 12:24:05 +02:00
|
|
|
} else {
|
2010-06-01 18:43:11 +02:00
|
|
|
skipExpression(tokPtr);
|
2010-04-19 22:35:58 +02:00
|
|
|
}
|
|
|
|
|
or_op = !okey; // tentatively force next evaluation
|
|
|
|
|
invert = false;
|
2010-06-01 18:43:11 +02:00
|
|
|
curr.clear();
|
2010-05-11 12:24:05 +02:00
|
|
|
continue;
|
2010-06-01 18:43:11 +02:00
|
|
|
default: {
|
|
|
|
|
const ushort *oTokPtr = --tokPtr;
|
|
|
|
|
evaluateExpression(tokPtr, &curr, false);
|
|
|
|
|
if (tokPtr != oTokPtr)
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
Q_ASSERT_X(false, "visitProBlock", "unexpected item type");
|
2010-04-19 22:35:58 +02:00
|
|
|
}
|
2010-04-29 21:43:41 +02:00
|
|
|
if (ret != ReturnTrue && ret != ReturnFalse)
|
2010-04-19 22:35:58 +02:00
|
|
|
break;
|
2010-02-02 21:00:09 +01:00
|
|
|
}
|
2010-04-19 22:35:58 +02:00
|
|
|
return ret;
|
2010-02-02 21:00:09 +01:00
|
|
|
}
|
|
|
|
|
|
2010-04-19 22:35:58 +02:00
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
void QMakeEvaluator::visitProFunctionDef(
|
2010-05-11 12:24:05 +02:00
|
|
|
ushort tok, const ProString &name, const ushort *tokPtr)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2012-05-02 18:25:24 +02:00
|
|
|
QHash<ProString, ProFunctionDef> *hash =
|
2010-05-11 12:24:05 +02:00
|
|
|
(tok == TokTestDef
|
2010-04-19 22:35:58 +02:00
|
|
|
? &m_functionDefs.testFunctions
|
|
|
|
|
: &m_functionDefs.replaceFunctions);
|
2012-05-02 18:25:24 +02:00
|
|
|
hash->insert(name, ProFunctionDef(m_current.pro, tokPtr - m_current.pro->tokPtr()));
|
2010-04-19 22:35:58 +02:00
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
QMakeEvaluator::VisitReturn QMakeEvaluator::visitProLoop(
|
2010-06-01 18:43:11 +02:00
|
|
|
const ProString &_variable, const ushort *exprPtr, const ushort *tokPtr)
|
2010-04-19 22:35:58 +02:00
|
|
|
{
|
2010-04-29 21:43:41 +02:00
|
|
|
VisitReturn ret = ReturnTrue;
|
2010-04-19 22:35:58 +02:00
|
|
|
bool infinite = false;
|
|
|
|
|
int index = 0;
|
2010-04-27 18:39:10 +02:00
|
|
|
ProString variable;
|
|
|
|
|
ProStringList oldVarVal;
|
2010-05-31 21:07:14 +02:00
|
|
|
ProString it_list = expandVariableReferences(exprPtr, 0, true).at(0);
|
2010-05-11 12:24:05 +02:00
|
|
|
if (_variable.isEmpty()) {
|
2010-04-19 22:35:58 +02:00
|
|
|
if (it_list != statics.strever) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("Invalid loop expression."));
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2009-05-18 17:46:30 +02:00
|
|
|
}
|
2010-04-27 18:39:10 +02:00
|
|
|
it_list = ProString(statics.strforever);
|
2009-05-14 14:35:37 +02:00
|
|
|
} else {
|
2010-05-11 12:24:05 +02:00
|
|
|
variable = map(_variable);
|
2010-04-19 22:35:58 +02:00
|
|
|
oldVarVal = valuesDirect(variable);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-04-27 18:39:10 +02:00
|
|
|
ProStringList list = valuesDirect(it_list);
|
2010-04-19 22:35:58 +02:00
|
|
|
if (list.isEmpty()) {
|
|
|
|
|
if (it_list == statics.strforever) {
|
|
|
|
|
infinite = true;
|
|
|
|
|
} else {
|
2010-04-27 18:39:10 +02:00
|
|
|
const QString &itl = it_list.toQString(m_tmp1);
|
|
|
|
|
int dotdot = itl.indexOf(statics.strDotDot);
|
2010-04-19 22:35:58 +02:00
|
|
|
if (dotdot != -1) {
|
|
|
|
|
bool ok;
|
2010-04-27 18:39:10 +02:00
|
|
|
int start = itl.left(dotdot).toInt(&ok);
|
2010-04-19 22:35:58 +02:00
|
|
|
if (ok) {
|
2010-04-27 18:39:10 +02:00
|
|
|
int end = itl.mid(dotdot+2).toInt(&ok);
|
2010-04-19 22:35:58 +02:00
|
|
|
if (ok) {
|
|
|
|
|
if (start < end) {
|
|
|
|
|
for (int i = start; i <= end; i++)
|
2010-04-27 18:39:10 +02:00
|
|
|
list << ProString(QString::number(i), NoHash);
|
2010-04-19 22:35:58 +02:00
|
|
|
} else {
|
|
|
|
|
for (int i = start; i >= end; i--)
|
2010-04-27 18:39:10 +02:00
|
|
|
list << ProString(QString::number(i), NoHash);
|
2010-02-02 21:00:09 +01:00
|
|
|
}
|
|
|
|
|
}
|
2010-04-19 22:35:58 +02:00
|
|
|
}
|
2010-02-02 21:00:09 +01:00
|
|
|
}
|
2008-12-16 10:48:49 +01:00
|
|
|
}
|
2008-12-12 18:10:42 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-04-19 22:35:58 +02:00
|
|
|
m_loopLevel++;
|
|
|
|
|
forever {
|
|
|
|
|
if (infinite) {
|
|
|
|
|
if (!variable.isEmpty())
|
2010-04-27 18:39:10 +02:00
|
|
|
m_valuemapStack.top()[variable] = ProStringList(ProString(QString::number(index++), NoHash));
|
2010-04-19 22:35:58 +02:00
|
|
|
if (index > 1000) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("ran into infinite loop (> 1000 iterations)."));
|
2010-04-19 22:35:58 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2010-04-27 18:39:10 +02:00
|
|
|
ProString val;
|
2010-04-19 22:35:58 +02:00
|
|
|
do {
|
|
|
|
|
if (index >= list.count())
|
|
|
|
|
goto do_break;
|
|
|
|
|
val = list.at(index++);
|
|
|
|
|
} while (val.isEmpty()); // stupid, but qmake is like that
|
2010-04-27 18:39:10 +02:00
|
|
|
m_valuemapStack.top()[variable] = ProStringList(val);
|
2010-04-19 22:35:58 +02:00
|
|
|
}
|
2009-05-19 19:00:06 +02:00
|
|
|
|
2010-05-11 12:24:05 +02:00
|
|
|
ret = visitProBlock(tokPtr);
|
2010-04-19 22:35:58 +02:00
|
|
|
switch (ret) {
|
2010-04-29 21:43:41 +02:00
|
|
|
case ReturnTrue:
|
|
|
|
|
case ReturnFalse:
|
2010-04-19 22:35:58 +02:00
|
|
|
break;
|
2010-04-29 21:43:41 +02:00
|
|
|
case ReturnNext:
|
|
|
|
|
ret = ReturnTrue;
|
2010-04-19 22:35:58 +02:00
|
|
|
break;
|
2010-04-29 21:43:41 +02:00
|
|
|
case ReturnBreak:
|
|
|
|
|
ret = ReturnTrue;
|
2010-04-19 22:35:58 +02:00
|
|
|
goto do_break;
|
|
|
|
|
default:
|
|
|
|
|
goto do_break;
|
2009-05-19 19:00:06 +02:00
|
|
|
}
|
|
|
|
|
}
|
2010-04-19 22:35:58 +02:00
|
|
|
do_break:
|
|
|
|
|
m_loopLevel--;
|
2009-05-19 19:00:06 +02:00
|
|
|
|
2010-04-19 22:35:58 +02:00
|
|
|
if (!variable.isEmpty())
|
|
|
|
|
m_valuemapStack.top()[variable] = oldVarVal;
|
|
|
|
|
return ret;
|
2009-05-19 19:00:06 +02:00
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
void QMakeEvaluator::visitProVariable(
|
2010-06-01 18:43:11 +02:00
|
|
|
ushort tok, const ProStringList &curr, const ushort *&tokPtr)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-05-31 21:07:14 +02:00
|
|
|
int sizeHint = *tokPtr++;
|
|
|
|
|
|
2010-06-01 18:43:11 +02:00
|
|
|
if (curr.size() != 1) {
|
|
|
|
|
skipExpression(tokPtr);
|
2011-04-06 21:26:20 +02:00
|
|
|
if (!m_cumulative || !curr.isEmpty())
|
|
|
|
|
evalError(fL1S("Left hand side of assignment must expand to exactly one word."));
|
2010-06-01 18:43:11 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const ProString &varName = map(curr.first());
|
|
|
|
|
|
2010-05-11 12:24:05 +02:00
|
|
|
if (tok == TokReplace) { // ~=
|
2010-01-14 12:34:46 +01:00
|
|
|
// DEFINES ~= s/a/b/?[gqi]
|
2009-07-14 20:42:45 +02:00
|
|
|
|
2010-05-31 21:07:14 +02:00
|
|
|
const ProStringList &varVal = expandVariableReferences(tokPtr, sizeHint, true);
|
2010-04-27 18:39:10 +02:00
|
|
|
const QString &val = varVal.at(0).toQString(m_tmp1);
|
2010-01-14 12:34:46 +01:00
|
|
|
if (val.length() < 4 || val.at(0) != QLatin1Char('s')) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("the ~= operator can handle only the s/// function."));
|
2010-01-14 12:34:46 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
QChar sep = val.at(1);
|
|
|
|
|
QStringList func = val.split(sep);
|
|
|
|
|
if (func.count() < 3 || func.count() > 4) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("the s/// function expects 3 or 4 arguments."));
|
2010-01-14 12:34:46 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool global = false, quote = false, case_sense = false;
|
|
|
|
|
if (func.count() == 4) {
|
|
|
|
|
global = func[3].indexOf(QLatin1Char('g')) != -1;
|
|
|
|
|
case_sense = func[3].indexOf(QLatin1Char('i')) == -1;
|
|
|
|
|
quote = func[3].indexOf(QLatin1Char('q')) != -1;
|
|
|
|
|
}
|
|
|
|
|
QString pattern = func[1];
|
|
|
|
|
QString replace = func[2];
|
|
|
|
|
if (quote)
|
|
|
|
|
pattern = QRegExp::escape(pattern);
|
|
|
|
|
|
|
|
|
|
QRegExp regexp(pattern, case_sense ? Qt::CaseSensitive : Qt::CaseInsensitive);
|
|
|
|
|
|
|
|
|
|
if (!m_skipLevel || m_cumulative) {
|
|
|
|
|
// We could make a union of modified and unmodified values,
|
|
|
|
|
// but this will break just as much as it fixes, so leave it as is.
|
2010-04-27 18:39:10 +02:00
|
|
|
replaceInList(&valuesRef(varName), regexp, replace, global, m_tmp2);
|
2010-01-14 12:34:46 +01:00
|
|
|
}
|
|
|
|
|
} else {
|
2010-05-31 21:07:14 +02:00
|
|
|
ProStringList varVal = expandVariableReferences(tokPtr, sizeHint);
|
2010-05-11 12:24:05 +02:00
|
|
|
switch (tok) {
|
|
|
|
|
default: // whatever - cannot happen
|
|
|
|
|
case TokAssign: // =
|
2009-07-14 20:42:45 +02:00
|
|
|
if (!m_cumulative) {
|
|
|
|
|
if (!m_skipLevel) {
|
2010-05-27 20:21:01 +02:00
|
|
|
zipEmpty(&varVal);
|
2010-02-09 20:38:21 +01:00
|
|
|
m_valuemapStack.top()[varName] = varVal;
|
2009-07-14 20:42:45 +02:00
|
|
|
}
|
|
|
|
|
} else {
|
2010-05-27 20:21:01 +02:00
|
|
|
zipEmpty(&varVal);
|
2010-06-24 15:17:28 +02:00
|
|
|
if (!varVal.isEmpty()) {
|
|
|
|
|
// We are greedy for values. But avoid exponential growth.
|
|
|
|
|
ProStringList &v = valuesRef(varName);
|
|
|
|
|
if (v.isEmpty()) {
|
|
|
|
|
v = varVal;
|
|
|
|
|
} else {
|
|
|
|
|
ProStringList old = v;
|
|
|
|
|
v = varVal;
|
|
|
|
|
QSet<ProString> has;
|
|
|
|
|
has.reserve(v.size());
|
|
|
|
|
foreach (const ProString &s, v)
|
|
|
|
|
has.insert(s);
|
|
|
|
|
v.reserve(v.size() + old.size());
|
|
|
|
|
foreach (const ProString &s, old)
|
|
|
|
|
if (!has.contains(s))
|
|
|
|
|
v << s;
|
|
|
|
|
}
|
2010-06-24 11:03:52 +02:00
|
|
|
}
|
2009-07-14 20:42:45 +02:00
|
|
|
}
|
|
|
|
|
break;
|
2010-05-11 12:24:05 +02:00
|
|
|
case TokAppendUnique: // *=
|
2011-04-20 18:19:33 +02:00
|
|
|
if (!m_skipLevel || m_cumulative)
|
2010-02-09 20:38:21 +01:00
|
|
|
insertUnique(&valuesRef(varName), varVal);
|
2009-07-14 20:42:45 +02:00
|
|
|
break;
|
2010-05-11 12:24:05 +02:00
|
|
|
case TokAppend: // +=
|
2009-07-14 20:42:45 +02:00
|
|
|
if (!m_skipLevel || m_cumulative) {
|
2010-05-27 20:21:01 +02:00
|
|
|
zipEmpty(&varVal);
|
2010-02-09 20:38:21 +01:00
|
|
|
valuesRef(varName) += varVal;
|
2009-07-14 20:42:45 +02:00
|
|
|
}
|
|
|
|
|
break;
|
2010-05-11 12:24:05 +02:00
|
|
|
case TokRemove: // -=
|
2009-07-14 20:42:45 +02:00
|
|
|
if (!m_cumulative) {
|
2011-04-20 18:19:33 +02:00
|
|
|
if (!m_skipLevel)
|
2010-02-09 20:38:21 +01:00
|
|
|
removeEach(&valuesRef(varName), varVal);
|
2009-07-14 20:42:45 +02:00
|
|
|
} else {
|
|
|
|
|
// We are stingy with our values, too.
|
|
|
|
|
}
|
|
|
|
|
break;
|
2010-01-14 12:34:46 +01:00
|
|
|
}
|
2009-07-14 20:42:45 +02:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
void QMakeEvaluator::visitCmdLine(const QString &cmds)
|
2011-03-18 20:03:22 +01:00
|
|
|
{
|
|
|
|
|
if (!cmds.isEmpty()) {
|
|
|
|
|
if (ProFile *pro = m_parser->parsedProBlock(fL1S("(command line)"), cmds)) {
|
|
|
|
|
m_locationStack.push(m_current);
|
|
|
|
|
visitProBlock(pro, pro->tokPtr());
|
|
|
|
|
m_current = m_locationStack.pop();
|
|
|
|
|
pro->deref();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
QMakeEvaluator::VisitReturn QMakeEvaluator::visitProFile(
|
|
|
|
|
ProFile *pro, QMakeEvaluatorHandler::EvalFileType type,
|
2010-06-24 16:41:33 +02:00
|
|
|
ProFileEvaluator::LoadFlags flags)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2011-02-09 20:00:44 +01:00
|
|
|
if (!m_cumulative && !pro->isOk())
|
|
|
|
|
return ReturnFalse;
|
|
|
|
|
|
2010-06-18 13:30:03 +02:00
|
|
|
m_handler->aboutToEval(currentProFile(), pro, type);
|
2009-07-22 17:46:25 +02:00
|
|
|
m_profileStack.push(pro);
|
2012-05-02 18:25:24 +02:00
|
|
|
if (flags & ProFileEvaluator::LoadPreFiles) {
|
2010-06-04 17:08:27 +02:00
|
|
|
#ifdef PROEVALUATOR_THREAD_SAFE
|
2010-06-24 16:41:33 +02:00
|
|
|
{
|
2010-06-04 17:08:27 +02:00
|
|
|
QMutexLocker locker(&m_option->mutex);
|
|
|
|
|
if (m_option->base_inProgress) {
|
|
|
|
|
QThreadPool::globalInstance()->releaseThread();
|
|
|
|
|
m_option->cond.wait(&m_option->mutex);
|
|
|
|
|
QThreadPool::globalInstance()->reserveThread();
|
|
|
|
|
} else
|
|
|
|
|
#endif
|
2009-08-04 16:16:27 +02:00
|
|
|
if (m_option->base_valuemap.isEmpty()) {
|
2010-06-04 17:08:27 +02:00
|
|
|
#ifdef PROEVALUATOR_THREAD_SAFE
|
|
|
|
|
m_option->base_inProgress = true;
|
|
|
|
|
locker.unlock();
|
|
|
|
|
#endif
|
|
|
|
|
|
2011-05-31 19:19:34 +02:00
|
|
|
#ifdef PROEVALUATOR_CUMULATIVE
|
2010-06-22 12:02:53 +02:00
|
|
|
bool cumulative = m_cumulative;
|
|
|
|
|
m_cumulative = false;
|
2011-05-31 19:19:34 +02:00
|
|
|
#endif
|
2010-06-22 12:02:53 +02:00
|
|
|
|
2009-08-04 16:16:27 +02:00
|
|
|
// ### init QMAKE_QMAKE, QMAKE_SH
|
|
|
|
|
// ### init QMAKE_EXT_{C,H,CPP,OBJ}
|
|
|
|
|
// ### init TEMPLATE_PREFIX
|
|
|
|
|
|
|
|
|
|
QString qmake_cache = m_option->cachefile;
|
|
|
|
|
if (qmake_cache.isEmpty() && !m_outputDir.isEmpty()) { //find it as it has not been specified
|
|
|
|
|
QDir dir(m_outputDir);
|
|
|
|
|
forever {
|
2010-01-22 12:26:14 +01:00
|
|
|
qmake_cache = dir.path() + QLatin1String("/.qmake.cache");
|
|
|
|
|
if (IoUtils::exists(qmake_cache))
|
2009-08-04 16:16:27 +02:00
|
|
|
break;
|
2009-08-05 12:18:36 +02:00
|
|
|
if (!dir.cdUp() || dir.isRoot()) {
|
2009-08-04 16:16:27 +02:00
|
|
|
qmake_cache.clear();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!qmake_cache.isEmpty()) {
|
2010-02-05 19:24:33 +01:00
|
|
|
qmake_cache = resolvePath(qmake_cache);
|
2010-04-27 18:39:10 +02:00
|
|
|
QHash<ProString, ProStringList> cache_valuemap;
|
2012-05-02 15:43:12 +02:00
|
|
|
if (evaluateFileInto(qmake_cache, QMakeEvaluatorHandler::EvalConfigFile,
|
2010-06-22 12:07:27 +02:00
|
|
|
&cache_valuemap, 0, EvalProOnly)) {
|
2009-08-04 16:16:27 +02:00
|
|
|
if (m_option->qmakespec.isEmpty()) {
|
2010-04-27 18:39:10 +02:00
|
|
|
const ProStringList &vals = cache_valuemap.value(ProString("QMAKESPEC"));
|
2009-08-04 16:16:27 +02:00
|
|
|
if (!vals.isEmpty())
|
2010-04-27 18:39:10 +02:00
|
|
|
m_option->qmakespec = vals.first().toQString();
|
2009-08-04 16:16:27 +02:00
|
|
|
}
|
2010-02-05 19:24:33 +01:00
|
|
|
} else {
|
|
|
|
|
qmake_cache.clear();
|
2009-08-04 16:16:27 +02:00
|
|
|
}
|
|
|
|
|
}
|
2010-02-05 19:24:33 +01:00
|
|
|
m_option->cachefile = qmake_cache;
|
2009-08-04 16:16:27 +02:00
|
|
|
|
|
|
|
|
QStringList mkspec_roots = qmakeMkspecPaths();
|
|
|
|
|
|
|
|
|
|
QString qmakespec = expandEnvVars(m_option->qmakespec);
|
|
|
|
|
if (qmakespec.isEmpty()) {
|
|
|
|
|
foreach (const QString &root, mkspec_roots) {
|
|
|
|
|
QString mkspec = root + QLatin1String("/default");
|
2010-01-22 12:26:14 +01:00
|
|
|
if (IoUtils::fileType(mkspec) == IoUtils::FileIsDir) {
|
2009-08-04 16:16:27 +02:00
|
|
|
qmakespec = mkspec;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (qmakespec.isEmpty()) {
|
2010-06-18 13:30:03 +02:00
|
|
|
m_handler->configError(fL1S("Could not find qmake configuration directory"));
|
2009-08-04 16:16:27 +02:00
|
|
|
// Unlike in qmake, not finding the spec is not critical ...
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-22 12:26:14 +01:00
|
|
|
if (IoUtils::isRelativePath(qmakespec)) {
|
2010-02-03 18:16:46 +01:00
|
|
|
if (IoUtils::exists(currentDirectory() + QLatin1Char('/') + qmakespec
|
|
|
|
|
+ QLatin1String("/qmake.conf"))) {
|
2010-01-22 12:26:14 +01:00
|
|
|
qmakespec = currentDirectory() + QLatin1Char('/') + qmakespec;
|
2009-08-04 16:16:27 +02:00
|
|
|
} else if (!m_outputDir.isEmpty()
|
2010-01-22 12:26:14 +01:00
|
|
|
&& IoUtils::exists(m_outputDir + QLatin1Char('/') + qmakespec
|
|
|
|
|
+ QLatin1String("/qmake.conf"))) {
|
2009-08-04 16:16:27 +02:00
|
|
|
qmakespec = m_outputDir + QLatin1Char('/') + qmakespec;
|
|
|
|
|
} else {
|
|
|
|
|
foreach (const QString &root, mkspec_roots) {
|
|
|
|
|
QString mkspec = root + QLatin1Char('/') + qmakespec;
|
2010-01-22 12:26:14 +01:00
|
|
|
if (IoUtils::exists(mkspec)) {
|
2009-08-04 16:16:27 +02:00
|
|
|
qmakespec = mkspec;
|
|
|
|
|
goto cool;
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-06-18 13:30:03 +02:00
|
|
|
m_handler->configError(fL1S("Could not find qmake configuration file"));
|
2009-08-04 16:16:27 +02:00
|
|
|
// Unlike in qmake, a missing config is not critical ...
|
|
|
|
|
qmakespec.clear();
|
|
|
|
|
cool: ;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!qmakespec.isEmpty()) {
|
|
|
|
|
m_option->qmakespec = QDir::cleanPath(qmakespec);
|
|
|
|
|
|
|
|
|
|
QString spec = m_option->qmakespec + QLatin1String("/qmake.conf");
|
2012-05-02 15:43:12 +02:00
|
|
|
if (!evaluateFileDirect(spec, QMakeEvaluatorHandler::EvalConfigFile,
|
2010-06-24 16:41:33 +02:00
|
|
|
ProFileEvaluator::LoadProOnly)) {
|
2010-06-18 13:30:03 +02:00
|
|
|
m_handler->configError(
|
|
|
|
|
fL1S("Could not read qmake configuration file %1").arg(spec));
|
2009-09-08 14:19:34 +02:00
|
|
|
} else if (!m_option->cachefile.isEmpty()) {
|
2010-06-24 16:41:33 +02:00
|
|
|
evaluateFileDirect(m_option->cachefile,
|
2012-05-02 15:43:12 +02:00
|
|
|
QMakeEvaluatorHandler::EvalConfigFile,
|
2010-06-24 16:41:33 +02:00
|
|
|
ProFileEvaluator::LoadProOnly);
|
2009-08-04 16:16:27 +02:00
|
|
|
}
|
2010-02-10 15:35:57 +01:00
|
|
|
m_option->qmakespec_name = IoUtils::fileName(m_option->qmakespec).toString();
|
|
|
|
|
if (m_option->qmakespec_name == QLatin1String("default")) {
|
|
|
|
|
#ifdef Q_OS_UNIX
|
|
|
|
|
char buffer[1024];
|
try to sort out the filename encoding mess
use local8bit instead of latin1 resp. 8bit-passthrough, after all.
the situation was as follows:
- if the pro files and file names were all ascii, everything just worked
- if either contained non-ascii:
- on unix, the evaluator would work as long as the file content
encoding matched the file name encoding, and the ui would work as
long as the file name encoding was latin1 (i.e., on no modern
system)
- on windows, both would work only if the ansi code page was
latin1/cp1252 (i.e., on western systems)
i.e., even in the low-level evaluator, only native latin1 systems with
actual latin1 files worked consistently. given this situation, it makes
little sense to make an encoding adapter between the evaluator and the
ui as originally planned. instead, take the easy way out and use
local8bit - this continues to work for native latin1 systems+files in
the backend, and makes the ui work for everything the backend groks and
some more.
Reviewed-by: dt
Task-number: QTCREATORBUG-930
2010-06-08 17:49:09 +02:00
|
|
|
int l = ::readlink(m_option->qmakespec.toLocal8Bit().constData(), buffer, 1024);
|
2010-02-10 15:35:57 +01:00
|
|
|
if (l != -1)
|
|
|
|
|
m_option->qmakespec_name =
|
try to sort out the filename encoding mess
use local8bit instead of latin1 resp. 8bit-passthrough, after all.
the situation was as follows:
- if the pro files and file names were all ascii, everything just worked
- if either contained non-ascii:
- on unix, the evaluator would work as long as the file content
encoding matched the file name encoding, and the ui would work as
long as the file name encoding was latin1 (i.e., on no modern
system)
- on windows, both would work only if the ansi code page was
latin1/cp1252 (i.e., on western systems)
i.e., even in the low-level evaluator, only native latin1 systems with
actual latin1 files worked consistently. given this situation, it makes
little sense to make an encoding adapter between the evaluator and the
ui as originally planned. instead, take the easy way out and use
local8bit - this continues to work for native latin1 systems+files in
the backend, and makes the ui work for everything the backend groks and
some more.
Reviewed-by: dt
Task-number: QTCREATORBUG-930
2010-06-08 17:49:09 +02:00
|
|
|
IoUtils::fileName(QString::fromLocal8Bit(buffer, l)).toString();
|
2010-02-10 15:35:57 +01:00
|
|
|
#else
|
|
|
|
|
// We can't resolve symlinks as they do on Unix, so configure.exe puts
|
|
|
|
|
// the source of the qmake.conf at the end of the default/qmake.conf in
|
|
|
|
|
// the QMAKESPEC_ORG variable.
|
2010-06-02 21:51:27 +02:00
|
|
|
const ProStringList &spec_org =
|
|
|
|
|
m_option->base_valuemap.value(ProString("QMAKESPEC_ORIGINAL"));
|
2010-02-10 15:35:57 +01:00
|
|
|
if (!spec_org.isEmpty())
|
|
|
|
|
m_option->qmakespec_name =
|
2010-06-02 21:51:27 +02:00
|
|
|
IoUtils::fileName(spec_org.first().toQString()).toString();
|
2010-02-10 15:35:57 +01:00
|
|
|
#endif
|
|
|
|
|
}
|
2009-08-04 16:16:27 +02:00
|
|
|
}
|
|
|
|
|
|
2010-06-22 12:02:53 +02:00
|
|
|
m_option->base_valuemap = m_valuemapStack.top();
|
|
|
|
|
m_option->base_functions = m_functionDefs;
|
|
|
|
|
|
2011-05-31 19:19:34 +02:00
|
|
|
#ifdef PROEVALUATOR_CUMULATIVE
|
2010-06-22 12:02:53 +02:00
|
|
|
m_cumulative = cumulative;
|
2011-05-31 19:19:34 +02:00
|
|
|
#endif
|
2010-06-04 17:08:27 +02:00
|
|
|
|
|
|
|
|
#ifdef PROEVALUATOR_THREAD_SAFE
|
|
|
|
|
locker.relock();
|
|
|
|
|
m_option->base_inProgress = false;
|
|
|
|
|
m_option->cond.wakeAll();
|
|
|
|
|
#endif
|
2010-06-22 12:02:53 +02:00
|
|
|
goto fresh;
|
2009-07-22 11:03:01 +02:00
|
|
|
}
|
2010-06-04 17:08:27 +02:00
|
|
|
#ifdef PROEVALUATOR_THREAD_SAFE
|
2010-06-24 16:41:33 +02:00
|
|
|
}
|
2010-06-04 17:08:27 +02:00
|
|
|
#endif
|
2009-08-04 16:16:27 +02:00
|
|
|
|
2010-02-09 20:38:21 +01:00
|
|
|
m_valuemapStack.top() = m_option->base_valuemap;
|
2009-08-10 17:27:07 +02:00
|
|
|
m_functionDefs = m_option->base_functions;
|
|
|
|
|
|
2010-06-22 12:02:53 +02:00
|
|
|
fresh:
|
2012-04-30 15:46:21 +02:00
|
|
|
evaluateFeatureFile(QLatin1String("default_pre.prf"));
|
|
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
ProStringList &tgt = m_valuemapStack.top()[ProString("TARGET")];
|
2009-07-29 11:30:33 +02:00
|
|
|
if (tgt.isEmpty())
|
2010-04-27 18:39:10 +02:00
|
|
|
tgt.append(ProString(QFileInfo(pro->fileName()).baseName(), NoHash));
|
2009-07-29 11:30:33 +02:00
|
|
|
|
2011-03-18 20:03:22 +01:00
|
|
|
visitCmdLine(m_option->precmds);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2010-06-23 14:51:43 +02:00
|
|
|
visitProBlock(pro, pro->tokPtr());
|
2009-07-28 18:54:03 +02:00
|
|
|
|
2012-05-02 18:25:24 +02:00
|
|
|
if (flags & ProFileEvaluator::LoadPostFiles) {
|
2011-03-18 20:03:22 +01:00
|
|
|
visitCmdLine(m_option->postcmds);
|
|
|
|
|
|
2009-07-22 11:03:01 +02:00
|
|
|
evaluateFeatureFile(QLatin1String("default_post.prf"));
|
|
|
|
|
|
|
|
|
|
QSet<QString> processed;
|
|
|
|
|
forever {
|
|
|
|
|
bool finished = true;
|
2010-04-27 18:39:10 +02:00
|
|
|
ProStringList configs = valuesDirect(statics.strCONFIG);
|
2009-07-22 11:03:01 +02:00
|
|
|
for (int i = configs.size() - 1; i >= 0; --i) {
|
2010-04-27 18:39:10 +02:00
|
|
|
QString config = configs.at(i).toQString(m_tmp1).toLower();
|
2009-07-22 11:03:01 +02:00
|
|
|
if (!processed.contains(config)) {
|
2010-04-27 18:39:10 +02:00
|
|
|
config.detach();
|
2009-07-22 11:03:01 +02:00
|
|
|
processed.insert(config);
|
|
|
|
|
if (evaluateFeatureFile(config)) {
|
|
|
|
|
finished = false;
|
|
|
|
|
break;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-07-22 11:03:01 +02:00
|
|
|
if (finished)
|
|
|
|
|
break;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
2009-07-22 17:46:25 +02:00
|
|
|
m_profileStack.pop();
|
2010-06-18 13:30:03 +02:00
|
|
|
m_handler->doneWithEval(currentProFile());
|
2009-07-22 17:46:25 +02:00
|
|
|
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnTrue;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
QStringList QMakeEvaluator::qmakeMkspecPaths() const
|
2009-07-23 16:34:30 +02:00
|
|
|
{
|
|
|
|
|
QStringList ret;
|
2009-08-04 16:16:27 +02:00
|
|
|
const QString concat = QLatin1String("/mkspecs");
|
|
|
|
|
|
2011-04-20 21:16:17 +02:00
|
|
|
QString qmakepath = m_option->getEnv(QLatin1String("QMAKEPATH"));
|
2009-08-04 16:16:27 +02:00
|
|
|
if (!qmakepath.isEmpty())
|
2011-04-20 21:16:17 +02:00
|
|
|
foreach (const QString &it, qmakepath.split(m_option->dirlist_sep))
|
2009-08-04 16:16:27 +02:00
|
|
|
ret << QDir::cleanPath(it) + concat;
|
|
|
|
|
|
2010-06-25 12:08:10 +02:00
|
|
|
QString builtIn = propertyValue(QLatin1String("QT_INSTALL_DATA"), false) + concat;
|
2010-01-21 18:24:46 +01:00
|
|
|
if (!ret.contains(builtIn))
|
|
|
|
|
ret << builtIn;
|
2009-07-23 16:34:30 +02:00
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
QStringList QMakeEvaluator::qmakeFeaturePaths() const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-07-31 16:47:18 +02:00
|
|
|
QString mkspecs_concat = QLatin1String("/mkspecs");
|
|
|
|
|
QString features_concat = QLatin1String("/features");
|
2008-12-02 12:01:29 +01:00
|
|
|
QStringList concat;
|
2011-03-18 20:41:40 +01:00
|
|
|
|
|
|
|
|
validateModes();
|
2009-07-31 16:47:18 +02:00
|
|
|
switch (m_option->target_mode) {
|
2012-05-02 15:20:08 +02:00
|
|
|
case QMakeGlobals::TARG_MACX_MODE:
|
2009-07-31 16:47:18 +02:00
|
|
|
concat << QLatin1String("/features/mac");
|
|
|
|
|
concat << QLatin1String("/features/macx");
|
|
|
|
|
concat << QLatin1String("/features/unix");
|
|
|
|
|
break;
|
2011-03-18 20:41:40 +01:00
|
|
|
default: // Can't happen, just make the compiler shut up
|
2012-05-02 15:20:08 +02:00
|
|
|
case QMakeGlobals::TARG_UNIX_MODE:
|
2009-07-31 16:47:18 +02:00
|
|
|
concat << QLatin1String("/features/unix");
|
|
|
|
|
break;
|
2012-05-02 15:20:08 +02:00
|
|
|
case QMakeGlobals::TARG_WIN_MODE:
|
2009-07-31 16:47:18 +02:00
|
|
|
concat << QLatin1String("/features/win32");
|
|
|
|
|
break;
|
2012-05-02 15:20:08 +02:00
|
|
|
case QMakeGlobals::TARG_SYMBIAN_MODE:
|
2011-03-18 20:41:40 +01:00
|
|
|
concat << QLatin1String("/features/symbian");
|
2009-07-31 16:47:18 +02:00
|
|
|
break;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2009-07-31 16:47:18 +02:00
|
|
|
concat << features_concat;
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
QStringList feature_roots;
|
2009-07-31 16:47:18 +02:00
|
|
|
|
2011-04-20 21:16:17 +02:00
|
|
|
QString mkspec_path = m_option->getEnv(QLatin1String("QMAKEFEATURES"));
|
2009-08-04 16:16:27 +02:00
|
|
|
if (!mkspec_path.isEmpty())
|
2011-04-20 21:16:17 +02:00
|
|
|
foreach (const QString &f, mkspec_path.split(m_option->dirlist_sep))
|
2010-02-05 19:24:33 +01:00
|
|
|
feature_roots += resolvePath(f);
|
2009-08-04 16:16:27 +02:00
|
|
|
|
2009-08-04 15:56:26 +02:00
|
|
|
feature_roots += propertyValue(QLatin1String("QMAKEFEATURES"), false).split(
|
2009-08-04 16:16:27 +02:00
|
|
|
m_option->dirlist_sep, QString::SkipEmptyParts);
|
|
|
|
|
|
|
|
|
|
if (!m_option->cachefile.isEmpty()) {
|
2010-02-05 19:24:33 +01:00
|
|
|
QString path = m_option->cachefile.left(m_option->cachefile.lastIndexOf((ushort)'/'));
|
2008-12-02 12:01:29 +01:00
|
|
|
foreach (const QString &concat_it, concat)
|
|
|
|
|
feature_roots << (path + concat_it);
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-20 21:16:17 +02:00
|
|
|
QString qmakepath = m_option->getEnv(QLatin1String("QMAKEPATH"));
|
2008-12-02 12:01:29 +01:00
|
|
|
if (!qmakepath.isNull()) {
|
2011-04-20 21:16:17 +02:00
|
|
|
const QStringList lst = qmakepath.split(m_option->dirlist_sep);
|
2008-12-02 12:01:29 +01:00
|
|
|
foreach (const QString &item, lst) {
|
2010-02-05 19:24:33 +01:00
|
|
|
QString citem = resolvePath(item);
|
2008-12-02 12:01:29 +01:00
|
|
|
foreach (const QString &concat_it, concat)
|
2009-08-04 16:16:27 +02:00
|
|
|
feature_roots << (citem + mkspecs_concat + concat_it);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!m_option->qmakespec.isEmpty()) {
|
2010-02-05 19:24:33 +01:00
|
|
|
QString qmakespec = resolvePath(m_option->qmakespec);
|
|
|
|
|
feature_roots << (qmakespec + features_concat);
|
2009-08-04 16:16:27 +02:00
|
|
|
|
2010-02-05 19:24:33 +01:00
|
|
|
QDir specdir(qmakespec);
|
2009-08-04 16:16:27 +02:00
|
|
|
while (!specdir.isRoot()) {
|
|
|
|
|
if (!specdir.cdUp() || specdir.isRoot())
|
|
|
|
|
break;
|
2010-01-22 12:26:14 +01:00
|
|
|
if (IoUtils::exists(specdir.path() + features_concat)) {
|
2009-08-04 16:16:27 +02:00
|
|
|
foreach (const QString &concat_it, concat)
|
|
|
|
|
feature_roots << (specdir.path() + concat_it);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
2009-08-04 16:16:27 +02:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
foreach (const QString &concat_it, concat)
|
2010-06-25 12:08:10 +02:00
|
|
|
feature_roots << (propertyValue(QLatin1String("QT_INSTALL_PREFIX"), false) +
|
2008-12-02 12:01:29 +01:00
|
|
|
mkspecs_concat + concat_it);
|
|
|
|
|
foreach (const QString &concat_it, concat)
|
2010-06-25 12:08:10 +02:00
|
|
|
feature_roots << (propertyValue(QLatin1String("QT_INSTALL_DATA"), false) +
|
2008-12-02 12:01:29 +01:00
|
|
|
mkspecs_concat + concat_it);
|
2009-08-04 16:16:27 +02:00
|
|
|
|
|
|
|
|
for (int i = 0; i < feature_roots.count(); ++i)
|
|
|
|
|
if (!feature_roots.at(i).endsWith((ushort)'/'))
|
|
|
|
|
feature_roots[i].append((ushort)'/');
|
|
|
|
|
|
2010-01-21 18:24:46 +01:00
|
|
|
feature_roots.removeDuplicates();
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
return feature_roots;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
QString QMakeEvaluator::propertyValue(const QString &name, bool complain) const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-08-04 16:12:11 +02:00
|
|
|
if (m_option->properties.contains(name))
|
|
|
|
|
return m_option->properties.value(name);
|
2008-12-02 12:01:29 +01:00
|
|
|
if (name == QLatin1String("QMAKE_MKSPECS"))
|
2009-07-23 18:36:59 +02:00
|
|
|
return qmakeMkspecPaths().join(m_option->dirlist_sep);
|
2008-12-02 12:01:29 +01:00
|
|
|
if (name == QLatin1String("QMAKE_VERSION"))
|
|
|
|
|
return QLatin1String("1.0"); //### FIXME
|
2009-08-04 15:56:26 +02:00
|
|
|
if (complain)
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("Querying unknown property %1").arg(name));
|
2009-08-04 15:21:40 +02:00
|
|
|
return QString();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
ProFile *QMakeEvaluator::currentProFile() const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
|
if (m_profileStack.count() > 0)
|
|
|
|
|
return m_profileStack.top();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
QString QMakeEvaluator::currentFileName() const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
|
ProFile *pro = currentProFile();
|
|
|
|
|
if (pro)
|
|
|
|
|
return pro->fileName();
|
|
|
|
|
return QString();
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
QString QMakeEvaluator::currentDirectory() const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
|
ProFile *cur = m_profileStack.top();
|
2008-12-19 21:35:10 +01:00
|
|
|
return cur->directoryName();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2010-01-14 18:02:22 +01:00
|
|
|
// The (QChar*)current->constData() constructs below avoid pointless detach() calls
|
2010-04-27 18:39:10 +02:00
|
|
|
// FIXME: This is inefficient. Should not make new string if it is a straight subsegment
|
2010-05-10 21:24:59 +02:00
|
|
|
static ALWAYS_INLINE void appendChar(ushort unicode,
|
2010-04-27 18:39:10 +02:00
|
|
|
QString *current, QChar **ptr, ProString *pending)
|
2010-01-14 18:02:22 +01:00
|
|
|
{
|
|
|
|
|
if (!pending->isEmpty()) {
|
|
|
|
|
int len = pending->size();
|
|
|
|
|
current->resize(current->size() + len);
|
|
|
|
|
::memcpy((QChar*)current->constData(), pending->constData(), len * 2);
|
|
|
|
|
pending->clear();
|
|
|
|
|
*ptr = (QChar*)current->constData() + len;
|
|
|
|
|
}
|
|
|
|
|
*(*ptr)++ = QChar(unicode);
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
static void appendString(const ProString &string,
|
|
|
|
|
QString *current, QChar **ptr, ProString *pending)
|
2010-01-14 18:02:22 +01:00
|
|
|
{
|
|
|
|
|
if (string.isEmpty())
|
|
|
|
|
return;
|
|
|
|
|
QChar *uc = (QChar*)current->constData();
|
|
|
|
|
int len;
|
|
|
|
|
if (*ptr != uc) {
|
|
|
|
|
len = *ptr - uc;
|
|
|
|
|
current->resize(current->size() + string.size());
|
|
|
|
|
} else if (!pending->isEmpty()) {
|
|
|
|
|
len = pending->size();
|
|
|
|
|
current->resize(current->size() + len + string.size());
|
|
|
|
|
::memcpy((QChar*)current->constData(), pending->constData(), len * 2);
|
|
|
|
|
pending->clear();
|
|
|
|
|
} else {
|
|
|
|
|
*pending = string;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
*ptr = (QChar*)current->constData() + len;
|
2010-04-27 18:39:10 +02:00
|
|
|
::memcpy(*ptr, string.constData(), string.size() * 2);
|
2010-01-14 18:02:22 +01:00
|
|
|
*ptr += string.size();
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
static void flushCurrent(ProStringList *ret,
|
|
|
|
|
QString *current, QChar **ptr, ProString *pending, bool joined)
|
2010-01-14 18:02:22 +01:00
|
|
|
{
|
|
|
|
|
QChar *uc = (QChar*)current->constData();
|
|
|
|
|
int len = *ptr - uc;
|
|
|
|
|
if (len) {
|
2010-04-27 18:39:10 +02:00
|
|
|
ret->append(ProString(QString(uc, len), NoHash));
|
2010-01-14 18:02:22 +01:00
|
|
|
*ptr = uc;
|
|
|
|
|
} else if (!pending->isEmpty()) {
|
|
|
|
|
ret->append(*pending);
|
|
|
|
|
pending->clear();
|
2010-04-27 22:00:11 +02:00
|
|
|
} else if (joined) {
|
2010-04-27 18:39:10 +02:00
|
|
|
ret->append(ProString());
|
2010-01-14 18:02:22 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
static inline void flushFinal(ProStringList *ret,
|
|
|
|
|
const QString ¤t, const QChar *ptr, const ProString &pending,
|
|
|
|
|
const ProString &str, bool replaced, bool joined)
|
2010-01-14 18:02:22 +01:00
|
|
|
{
|
|
|
|
|
int len = ptr - current.data();
|
|
|
|
|
if (len) {
|
|
|
|
|
if (!replaced && len == str.size())
|
|
|
|
|
ret->append(str);
|
|
|
|
|
else
|
2010-04-27 18:39:10 +02:00
|
|
|
ret->append(ProString(QString(current.data(), len), NoHash));
|
2010-01-14 18:02:22 +01:00
|
|
|
} else if (!pending.isEmpty()) {
|
|
|
|
|
ret->append(pending);
|
2010-04-27 22:00:11 +02:00
|
|
|
} else if (joined) {
|
2010-04-27 18:39:10 +02:00
|
|
|
ret->append(ProString());
|
2010-01-14 18:02:22 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
ProStringList QMakeEvaluator::expandVariableReferences(
|
2010-04-27 18:39:10 +02:00
|
|
|
const ProString &str, int *pos, bool joined)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-04-27 18:39:10 +02:00
|
|
|
ProStringList ret;
|
2009-03-11 17:47:43 +01:00
|
|
|
// if (ok)
|
|
|
|
|
// *ok = true;
|
2010-04-28 14:32:46 +02:00
|
|
|
if (str.isEmpty() && !pos)
|
2008-12-02 12:01:29 +01:00
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
const ushort LSQUARE = '[';
|
|
|
|
|
const ushort RSQUARE = ']';
|
|
|
|
|
const ushort LCURLY = '{';
|
|
|
|
|
const ushort RCURLY = '}';
|
|
|
|
|
const ushort LPAREN = '(';
|
|
|
|
|
const ushort RPAREN = ')';
|
|
|
|
|
const ushort DOLLAR = '$';
|
|
|
|
|
const ushort BACKSLASH = '\\';
|
|
|
|
|
const ushort UNDERSCORE = '_';
|
|
|
|
|
const ushort DOT = '.';
|
|
|
|
|
const ushort SPACE = ' ';
|
|
|
|
|
const ushort TAB = '\t';
|
2010-01-19 12:31:39 +01:00
|
|
|
const ushort COMMA = ',';
|
2009-03-11 17:47:43 +01:00
|
|
|
const ushort SINGLEQUOTE = '\'';
|
|
|
|
|
const ushort DOUBLEQUOTE = '"';
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-01-19 12:31:39 +01:00
|
|
|
ushort unicode, quote = 0, parens = 0;
|
2010-04-27 18:39:10 +02:00
|
|
|
const ushort *str_data = (const ushort *)str.constData();
|
|
|
|
|
const int str_len = str.size();
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
ProString var, args;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-01-14 18:02:22 +01:00
|
|
|
bool replaced = false;
|
2010-04-27 22:00:11 +02:00
|
|
|
bool putSpace = false;
|
2010-01-14 18:02:22 +01:00
|
|
|
QString current; // Buffer for successively assembled string segments
|
|
|
|
|
current.resize(str.size());
|
|
|
|
|
QChar *ptr = current.data();
|
2010-04-27 18:39:10 +02:00
|
|
|
ProString pending; // Buffer for string segments from variables
|
2010-01-14 18:02:22 +01:00
|
|
|
// Only one of the above buffers can be filled at a given time.
|
2010-01-19 12:31:39 +01:00
|
|
|
for (int i = pos ? *pos : 0; i < str_len; ++i) {
|
2010-01-22 16:20:44 +01:00
|
|
|
unicode = str_data[i];
|
2010-01-14 18:02:22 +01:00
|
|
|
if (unicode == DOLLAR) {
|
2010-01-22 16:20:44 +01:00
|
|
|
if (str_len > i+2 && str_data[i+1] == DOLLAR) {
|
2010-01-14 18:02:22 +01:00
|
|
|
++i;
|
|
|
|
|
ushort term = 0;
|
2008-12-02 12:01:29 +01:00
|
|
|
enum { VAR, ENVIRON, FUNCTION, PROPERTY } var_type = VAR;
|
2010-01-22 16:20:44 +01:00
|
|
|
unicode = str_data[++i];
|
2009-03-11 17:47:43 +01:00
|
|
|
if (unicode == LSQUARE) {
|
2010-01-22 16:20:44 +01:00
|
|
|
unicode = str_data[++i];
|
2008-12-02 12:01:29 +01:00
|
|
|
term = RSQUARE;
|
|
|
|
|
var_type = PROPERTY;
|
2009-03-11 17:47:43 +01:00
|
|
|
} else if (unicode == LCURLY) {
|
2010-01-22 16:20:44 +01:00
|
|
|
unicode = str_data[++i];
|
2008-12-02 12:01:29 +01:00
|
|
|
var_type = VAR;
|
|
|
|
|
term = RCURLY;
|
2009-03-11 17:47:43 +01:00
|
|
|
} else if (unicode == LPAREN) {
|
2010-01-22 16:20:44 +01:00
|
|
|
unicode = str_data[++i];
|
2008-12-02 12:01:29 +01:00
|
|
|
var_type = ENVIRON;
|
|
|
|
|
term = RPAREN;
|
|
|
|
|
}
|
2010-01-14 18:02:22 +01:00
|
|
|
int name_start = i;
|
2009-03-11 17:47:43 +01:00
|
|
|
forever {
|
|
|
|
|
if (!(unicode & (0xFF<<8)) &&
|
|
|
|
|
unicode != DOT && unicode != UNDERSCORE &&
|
|
|
|
|
//unicode != SINGLEQUOTE && unicode != DOUBLEQUOTE &&
|
|
|
|
|
(unicode < 'a' || unicode > 'z') && (unicode < 'A' || unicode > 'Z') &&
|
|
|
|
|
(unicode < '0' || unicode > '9'))
|
2008-12-02 12:01:29 +01:00
|
|
|
break;
|
|
|
|
|
if (++i == str_len)
|
|
|
|
|
break;
|
2010-01-22 16:20:44 +01:00
|
|
|
unicode = str_data[i];
|
2009-03-11 17:47:43 +01:00
|
|
|
// at this point, i points to either the 'term' or 'next' character (which is in unicode)
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-04-27 18:39:10 +02:00
|
|
|
var = str.mid(name_start, i - name_start);
|
2009-03-11 17:47:43 +01:00
|
|
|
if (var_type == VAR && unicode == LPAREN) {
|
2008-12-02 12:01:29 +01:00
|
|
|
var_type = FUNCTION;
|
2010-01-14 18:02:22 +01:00
|
|
|
name_start = i + 1;
|
2008-12-02 12:01:29 +01:00
|
|
|
int depth = 0;
|
2009-03-11 17:47:43 +01:00
|
|
|
forever {
|
2008-12-02 12:01:29 +01:00
|
|
|
if (++i == str_len)
|
|
|
|
|
break;
|
2010-01-22 16:20:44 +01:00
|
|
|
unicode = str_data[i];
|
2009-03-11 17:47:43 +01:00
|
|
|
if (unicode == LPAREN) {
|
2008-12-02 12:01:29 +01:00
|
|
|
depth++;
|
2009-03-11 17:47:43 +01:00
|
|
|
} else if (unicode == RPAREN) {
|
2008-12-02 12:01:29 +01:00
|
|
|
if (!depth)
|
|
|
|
|
break;
|
|
|
|
|
--depth;
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-04-27 18:39:10 +02:00
|
|
|
args = str.mid(name_start, i - name_start);
|
2009-03-11 17:47:43 +01:00
|
|
|
if (++i < str_len)
|
2010-01-22 16:20:44 +01:00
|
|
|
unicode = str_data[i];
|
2008-12-02 12:01:29 +01:00
|
|
|
else
|
2009-03-11 17:47:43 +01:00
|
|
|
unicode = 0;
|
|
|
|
|
// at this point i is pointing to the 'next' character (which is in unicode)
|
|
|
|
|
// this might actually be a term character since you can do $${func()}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
if (term) {
|
2009-03-11 17:47:43 +01:00
|
|
|
if (unicode != term) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("Missing %1 terminator [found %2]")
|
|
|
|
|
.arg(QChar(term))
|
|
|
|
|
.arg(unicode ? QString(unicode) : fL1S("end-of-line")));
|
2009-03-11 17:47:43 +01:00
|
|
|
// if (ok)
|
|
|
|
|
// *ok = false;
|
2010-01-19 12:31:39 +01:00
|
|
|
if (pos)
|
|
|
|
|
*pos = str_len;
|
2010-04-27 18:39:10 +02:00
|
|
|
return ProStringList();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2009-03-11 17:47:43 +01:00
|
|
|
} else {
|
|
|
|
|
// move the 'cursor' back to the last char of the thing we were looking at
|
|
|
|
|
--i;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
ProStringList replacement;
|
2008-12-02 12:01:29 +01:00
|
|
|
if (var_type == ENVIRON) {
|
2011-04-20 21:16:17 +02:00
|
|
|
replacement = split_value_list(m_option->getEnv(var.toQString(m_tmp1)));
|
2008-12-02 12:01:29 +01:00
|
|
|
} else if (var_type == PROPERTY) {
|
2010-06-25 12:08:10 +02:00
|
|
|
replacement << ProString(propertyValue(var.toQString(m_tmp1), true), NoHash);
|
2008-12-02 12:01:29 +01:00
|
|
|
} else if (var_type == FUNCTION) {
|
2010-04-27 18:39:10 +02:00
|
|
|
replacement += evaluateExpandFunction(var, args);
|
2008-12-02 12:01:29 +01:00
|
|
|
} else if (var_type == VAR) {
|
2010-02-11 16:33:16 +01:00
|
|
|
replacement = values(map(var));
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
if (!replacement.isEmpty()) {
|
2010-04-27 22:00:11 +02:00
|
|
|
if (quote || joined) {
|
|
|
|
|
if (putSpace) {
|
|
|
|
|
putSpace = false;
|
|
|
|
|
if (!replacement.at(0).isEmpty()) // Bizarre, indeed
|
|
|
|
|
appendChar(' ', ¤t, &ptr, &pending);
|
|
|
|
|
}
|
2010-04-27 18:39:10 +02:00
|
|
|
appendString(ProString(replacement.join(statics.field_sep), NoHash),
|
2010-01-14 18:02:22 +01:00
|
|
|
¤t, &ptr, &pending);
|
2009-03-11 17:47:43 +01:00
|
|
|
} else {
|
2010-04-06 19:56:58 +02:00
|
|
|
appendString(replacement.at(0), ¤t, &ptr, &pending);
|
2010-01-14 18:02:22 +01:00
|
|
|
if (replacement.size() > 1) {
|
2010-04-27 22:00:11 +02:00
|
|
|
flushCurrent(&ret, ¤t, &ptr, &pending, false);
|
2010-04-06 19:56:58 +02:00
|
|
|
int j = 1;
|
2010-01-14 18:02:22 +01:00
|
|
|
if (replacement.size() > 2) {
|
|
|
|
|
// FIXME: ret.reserve(ret.size() + replacement.size() - 2);
|
2010-04-06 19:56:58 +02:00
|
|
|
for (; j < replacement.size() - 1; ++j)
|
|
|
|
|
ret << replacement.at(j);
|
2010-01-14 18:02:22 +01:00
|
|
|
}
|
2010-04-06 19:56:58 +02:00
|
|
|
pending = replacement.at(j);
|
2009-03-11 17:47:43 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-01-14 18:02:22 +01:00
|
|
|
replaced = true;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-01-14 18:02:22 +01:00
|
|
|
continue;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2009-03-11 17:47:43 +01:00
|
|
|
} else if (unicode == BACKSLASH) {
|
2010-01-14 18:02:22 +01:00
|
|
|
static const char symbols[] = "[]{}()$\\'\"";
|
2010-01-22 16:20:44 +01:00
|
|
|
ushort unicode2 = str_data[i+1];
|
2010-01-14 18:02:22 +01:00
|
|
|
if (!(unicode2 & 0xff00) && strchr(symbols, unicode2)) {
|
|
|
|
|
unicode = unicode2;
|
|
|
|
|
++i;
|
2009-03-11 17:47:43 +01:00
|
|
|
}
|
2010-01-14 18:02:22 +01:00
|
|
|
} else if (quote) {
|
|
|
|
|
if (unicode == quote) {
|
|
|
|
|
quote = 0;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (unicode == SINGLEQUOTE || unicode == DOUBLEQUOTE) {
|
|
|
|
|
quote = unicode;
|
|
|
|
|
continue;
|
2010-04-01 16:33:48 +02:00
|
|
|
} else if (unicode == SPACE || unicode == TAB) {
|
2010-04-27 22:00:11 +02:00
|
|
|
if (!joined)
|
|
|
|
|
flushCurrent(&ret, ¤t, &ptr, &pending, false);
|
|
|
|
|
else if ((ptr - (QChar*)current.constData()) || !pending.isEmpty())
|
|
|
|
|
putSpace = true;
|
2010-01-14 18:02:22 +01:00
|
|
|
continue;
|
2010-01-19 12:31:39 +01:00
|
|
|
} else if (pos) {
|
|
|
|
|
if (unicode == LPAREN) {
|
|
|
|
|
++parens;
|
|
|
|
|
} else if (unicode == RPAREN) {
|
|
|
|
|
--parens;
|
|
|
|
|
} else if (!parens && unicode == COMMA) {
|
2010-04-27 22:00:11 +02:00
|
|
|
if (!joined) {
|
|
|
|
|
*pos = i + 1;
|
|
|
|
|
flushFinal(&ret, current, ptr, pending, str, replaced, false);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
flushCurrent(&ret, ¤t, &ptr, &pending, true);
|
|
|
|
|
putSpace = false;
|
|
|
|
|
continue;
|
2010-01-19 12:31:39 +01:00
|
|
|
}
|
2009-03-11 17:47:43 +01:00
|
|
|
}
|
|
|
|
|
}
|
2010-04-27 22:00:11 +02:00
|
|
|
if (putSpace) {
|
|
|
|
|
putSpace = false;
|
|
|
|
|
appendChar(' ', ¤t, &ptr, &pending);
|
|
|
|
|
}
|
2010-01-14 18:02:22 +01:00
|
|
|
appendChar(unicode, ¤t, &ptr, &pending);
|
2010-01-14 17:43:02 +01:00
|
|
|
}
|
2010-01-19 12:31:39 +01:00
|
|
|
if (pos)
|
|
|
|
|
*pos = str_len;
|
2010-04-27 22:00:11 +02:00
|
|
|
flushFinal(&ret, current, ptr, pending, str, replaced, joined);
|
2008-12-02 12:01:29 +01:00
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
bool QMakeEvaluator::modesForGenerator(const QString &gen,
|
2012-05-02 15:20:08 +02:00
|
|
|
QMakeGlobals::HOST_MODE *host_mode, QMakeGlobals::TARG_MODE *target_mode) const
|
2011-03-18 20:41:40 +01:00
|
|
|
{
|
|
|
|
|
if (gen == fL1S("UNIX")) {
|
|
|
|
|
#ifdef Q_OS_MAC
|
2012-05-02 15:20:08 +02:00
|
|
|
*host_mode = QMakeGlobals::HOST_MACX_MODE;
|
|
|
|
|
*target_mode = QMakeGlobals::TARG_MACX_MODE;
|
2011-03-18 20:41:40 +01:00
|
|
|
#else
|
2012-05-02 15:20:08 +02:00
|
|
|
*host_mode = QMakeGlobals::HOST_UNIX_MODE;
|
|
|
|
|
*target_mode = QMakeGlobals::TARG_UNIX_MODE;
|
2011-03-18 20:41:40 +01:00
|
|
|
#endif
|
|
|
|
|
} else if (gen == fL1S("MSVC.NET") || gen == fL1S("BMAKE") || gen == fL1S("MSBUILD")) {
|
2012-05-02 15:20:08 +02:00
|
|
|
*host_mode = QMakeGlobals::HOST_WIN_MODE;
|
|
|
|
|
*target_mode = QMakeGlobals::TARG_WIN_MODE;
|
2011-03-18 20:41:40 +01:00
|
|
|
} else if (gen == fL1S("MINGW")) {
|
|
|
|
|
#if defined(Q_OS_MAC)
|
2012-05-02 15:20:08 +02:00
|
|
|
*host_mode = QMakeGlobals::HOST_MACX_MODE;
|
2011-03-18 20:41:40 +01:00
|
|
|
#elif defined(Q_OS_UNIX)
|
2012-05-02 15:20:08 +02:00
|
|
|
*host_mode = QMakeGlobals::HOST_UNIX_MODE;
|
2011-03-18 20:41:40 +01:00
|
|
|
#else
|
2012-05-02 15:20:08 +02:00
|
|
|
*host_mode = QMakeGlobals::HOST_WIN_MODE;
|
2011-03-18 20:41:40 +01:00
|
|
|
#endif
|
2012-05-02 15:20:08 +02:00
|
|
|
*target_mode = QMakeGlobals::TARG_WIN_MODE;
|
2011-03-18 20:41:40 +01:00
|
|
|
} else if (gen == fL1S("PROJECTBUILDER") || gen == fL1S("XCODE")) {
|
2012-05-02 15:20:08 +02:00
|
|
|
*host_mode = QMakeGlobals::HOST_MACX_MODE;
|
|
|
|
|
*target_mode = QMakeGlobals::TARG_MACX_MODE;
|
2011-03-18 20:41:40 +01:00
|
|
|
} else if (gen == fL1S("SYMBIAN_ABLD") || gen == fL1S("SYMBIAN_SBSV2")
|
|
|
|
|
|| gen == fL1S("SYMBIAN_UNIX") || gen == fL1S("SYMBIAN_MINGW")) {
|
|
|
|
|
#if defined(Q_OS_MAC)
|
2012-05-02 15:20:08 +02:00
|
|
|
*host_mode = QMakeGlobals::HOST_MACX_MODE;
|
2011-03-18 20:41:40 +01:00
|
|
|
#elif defined(Q_OS_UNIX)
|
2012-05-02 15:20:08 +02:00
|
|
|
*host_mode = QMakeGlobals::HOST_UNIX_MODE;
|
2011-03-18 20:41:40 +01:00
|
|
|
#else
|
2012-05-02 15:20:08 +02:00
|
|
|
*host_mode = QMakeGlobals::HOST_WIN_MODE;
|
2011-03-18 20:41:40 +01:00
|
|
|
#endif
|
2012-05-02 15:20:08 +02:00
|
|
|
*target_mode = QMakeGlobals::TARG_SYMBIAN_MODE;
|
2011-03-18 20:41:40 +01:00
|
|
|
} else {
|
|
|
|
|
evalError(fL1S("Unknown generator specified: %1").arg(gen));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
void QMakeEvaluator::validateModes() const
|
2011-03-18 20:41:40 +01:00
|
|
|
{
|
2012-05-02 15:20:08 +02:00
|
|
|
if (m_option->host_mode == QMakeGlobals::HOST_UNKNOWN_MODE
|
|
|
|
|
|| m_option->target_mode == QMakeGlobals::TARG_UNKNOWN_MODE) {
|
2011-03-18 20:41:40 +01:00
|
|
|
const QHash<ProString, ProStringList> &vals =
|
|
|
|
|
m_option->base_valuemap.isEmpty() ? m_valuemapStack[0] : m_option->base_valuemap;
|
2012-05-02 15:20:08 +02:00
|
|
|
QMakeGlobals::HOST_MODE host_mode;
|
|
|
|
|
QMakeGlobals::TARG_MODE target_mode;
|
2011-03-18 20:41:40 +01:00
|
|
|
const ProStringList &gen = vals.value(ProString("MAKEFILE_GENERATOR"));
|
|
|
|
|
if (gen.isEmpty()) {
|
|
|
|
|
evalError(fL1S("Using OS scope before setting MAKEFILE_GENERATOR"));
|
|
|
|
|
} else if (modesForGenerator(gen.at(0).toQString(), &host_mode, &target_mode)) {
|
2012-05-02 15:20:08 +02:00
|
|
|
if (m_option->host_mode == QMakeGlobals::HOST_UNKNOWN_MODE) {
|
2011-03-18 20:41:40 +01:00
|
|
|
m_option->host_mode = host_mode;
|
|
|
|
|
m_option->applyHostMode();
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:20:08 +02:00
|
|
|
if (m_option->target_mode == QMakeGlobals::TARG_UNKNOWN_MODE) {
|
2011-03-18 20:41:40 +01:00
|
|
|
const ProStringList &tgt = vals.value(ProString("TARGET_PLATFORM"));
|
|
|
|
|
if (!tgt.isEmpty()) {
|
|
|
|
|
const QString &os = tgt.at(0).toQString();
|
|
|
|
|
if (os == statics.strunix)
|
2012-05-02 15:20:08 +02:00
|
|
|
m_option->target_mode = QMakeGlobals::TARG_UNIX_MODE;
|
2011-03-18 20:41:40 +01:00
|
|
|
else if (os == statics.strmacx)
|
2012-05-02 15:20:08 +02:00
|
|
|
m_option->target_mode = QMakeGlobals::TARG_MACX_MODE;
|
2011-03-18 20:41:40 +01:00
|
|
|
else if (os == statics.strsymbian)
|
2012-05-02 15:20:08 +02:00
|
|
|
m_option->target_mode = QMakeGlobals::TARG_SYMBIAN_MODE;
|
2011-03-18 20:41:40 +01:00
|
|
|
else if (os == statics.strwin32)
|
2012-05-02 15:20:08 +02:00
|
|
|
m_option->target_mode = QMakeGlobals::TARG_WIN_MODE;
|
2011-03-18 20:41:40 +01:00
|
|
|
else
|
|
|
|
|
evalError(fL1S("Unknown target platform specified: %1").arg(os));
|
|
|
|
|
} else {
|
|
|
|
|
m_option->target_mode = target_mode;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
bool QMakeEvaluator::isActiveConfig(const QString &config, bool regex)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
|
// magic types for easy flipping
|
2010-02-08 17:15:44 +01:00
|
|
|
if (config == statics.strtrue)
|
2008-12-02 12:01:29 +01:00
|
|
|
return true;
|
2010-02-08 17:15:44 +01:00
|
|
|
if (config == statics.strfalse)
|
2008-12-02 12:01:29 +01:00
|
|
|
return false;
|
|
|
|
|
|
2011-03-18 20:41:40 +01:00
|
|
|
if (config == statics.strunix) {
|
|
|
|
|
validateModes();
|
2012-05-02 15:20:08 +02:00
|
|
|
return m_option->target_mode == QMakeGlobals::TARG_UNIX_MODE
|
|
|
|
|
|| m_option->target_mode == QMakeGlobals::TARG_MACX_MODE
|
|
|
|
|
|| m_option->target_mode == QMakeGlobals::TARG_SYMBIAN_MODE;
|
2011-03-18 20:41:40 +01:00
|
|
|
} else if (config == statics.strmacx || config == statics.strmac) {
|
|
|
|
|
validateModes();
|
2012-05-02 15:20:08 +02:00
|
|
|
return m_option->target_mode == QMakeGlobals::TARG_MACX_MODE;
|
2011-03-18 20:41:40 +01:00
|
|
|
} else if (config == statics.strsymbian) {
|
|
|
|
|
validateModes();
|
2012-05-02 15:20:08 +02:00
|
|
|
return m_option->target_mode == QMakeGlobals::TARG_SYMBIAN_MODE;
|
2011-03-18 20:41:40 +01:00
|
|
|
} else if (config == statics.strwin32) {
|
|
|
|
|
validateModes();
|
2012-05-02 15:20:08 +02:00
|
|
|
return m_option->target_mode == QMakeGlobals::TARG_WIN_MODE;
|
2011-03-18 20:41:40 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-01-19 18:36:03 +01:00
|
|
|
if (regex && (config.contains(QLatin1Char('*')) || config.contains(QLatin1Char('?')))) {
|
2010-04-27 18:39:10 +02:00
|
|
|
QString cfg = config;
|
|
|
|
|
cfg.detach(); // Keep m_tmp out of QRegExp's cache
|
|
|
|
|
QRegExp re(cfg, Qt::CaseSensitive, QRegExp::Wildcard);
|
2009-07-02 11:05:01 +10:00
|
|
|
|
2011-03-18 20:41:40 +01:00
|
|
|
// mkspecs
|
2010-02-10 15:35:57 +01:00
|
|
|
if (re.exactMatch(m_option->qmakespec_name))
|
2009-07-02 11:05:01 +10:00
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
// CONFIG variable
|
2010-04-27 18:39:10 +02:00
|
|
|
int t = 0;
|
|
|
|
|
foreach (const ProString &configValue, valuesDirect(statics.strCONFIG)) {
|
|
|
|
|
if (re.exactMatch(configValue.toQString(m_tmp[t])))
|
2009-07-02 11:05:01 +10:00
|
|
|
return true;
|
2010-04-27 18:39:10 +02:00
|
|
|
t ^= 1;
|
2009-07-02 11:05:01 +10:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// mkspecs
|
2010-02-10 15:35:57 +01:00
|
|
|
if (m_option->qmakespec_name == config)
|
2009-07-02 11:05:01 +10:00
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
// CONFIG variable
|
2010-04-27 18:39:10 +02:00
|
|
|
if (valuesDirect(statics.strCONFIG).contains(ProString(config, NoHash)))
|
2010-04-29 17:03:39 +02:00
|
|
|
return true;
|
2009-07-02 11:05:01 +10:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
ProStringList QMakeEvaluator::expandVariableReferences(
|
2010-05-31 21:07:14 +02:00
|
|
|
const ushort *&tokPtr, int sizeHint, bool joined)
|
2010-06-01 18:43:11 +02:00
|
|
|
{
|
|
|
|
|
ProStringList ret;
|
2010-05-31 21:07:14 +02:00
|
|
|
ret.reserve(sizeHint);
|
2010-06-01 18:43:11 +02:00
|
|
|
forever {
|
|
|
|
|
evaluateExpression(tokPtr, &ret, joined);
|
|
|
|
|
switch (*tokPtr) {
|
|
|
|
|
case TokValueTerminator:
|
|
|
|
|
case TokFuncTerminator:
|
|
|
|
|
tokPtr++;
|
|
|
|
|
return ret;
|
|
|
|
|
case TokArgSeparator:
|
|
|
|
|
if (joined) {
|
|
|
|
|
tokPtr++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
// fallthrough
|
|
|
|
|
default:
|
|
|
|
|
Q_ASSERT_X(false, "expandVariableReferences", "Unrecognized token");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
void QMakeEvaluator::populateDeps(
|
2011-07-11 15:40:07 +02:00
|
|
|
const ProStringList &deps, const ProString &prefix,
|
|
|
|
|
QHash<ProString, QSet<ProString> > &dependencies, QHash<ProString, ProStringList> &dependees,
|
|
|
|
|
ProStringList &rootSet) const
|
|
|
|
|
{
|
|
|
|
|
foreach (const ProString &item, deps)
|
|
|
|
|
if (!dependencies.contains(item)) {
|
|
|
|
|
QSet<ProString> &dset = dependencies[item]; // Always create entry
|
|
|
|
|
ProStringList depends = valuesDirect(ProString(prefix + item + QString::fromLatin1(".depends")));
|
|
|
|
|
if (depends.isEmpty()) {
|
|
|
|
|
rootSet << item;
|
|
|
|
|
} else {
|
|
|
|
|
foreach (const ProString &dep, depends) {
|
|
|
|
|
dset.insert(dep);
|
|
|
|
|
dependees[dep] << item;
|
|
|
|
|
}
|
|
|
|
|
populateDeps(depends, prefix, dependencies, dependees, rootSet);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
QList<ProStringList> QMakeEvaluator::prepareFunctionArgs(const ushort *&tokPtr)
|
2010-06-01 18:43:11 +02:00
|
|
|
{
|
|
|
|
|
QList<ProStringList> args_list;
|
|
|
|
|
if (*tokPtr != TokFuncTerminator) {
|
|
|
|
|
for (;; tokPtr++) {
|
|
|
|
|
ProStringList arg;
|
|
|
|
|
evaluateExpression(tokPtr, &arg, false);
|
|
|
|
|
args_list << arg;
|
|
|
|
|
if (*tokPtr == TokFuncTerminator)
|
|
|
|
|
break;
|
|
|
|
|
Q_ASSERT(*tokPtr == TokArgSeparator);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
tokPtr++;
|
|
|
|
|
return args_list;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
QList<ProStringList> QMakeEvaluator::prepareFunctionArgs(const ProString &arguments)
|
2009-08-14 17:36:07 +02:00
|
|
|
{
|
2010-04-27 18:39:10 +02:00
|
|
|
QList<ProStringList> args_list;
|
|
|
|
|
for (int pos = 0; pos < arguments.size(); )
|
2010-04-01 16:33:48 +02:00
|
|
|
args_list << expandVariableReferences(arguments, &pos);
|
2009-08-14 17:36:07 +02:00
|
|
|
return args_list;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
ProStringList QMakeEvaluator::evaluateFunction(
|
2012-05-02 18:25:24 +02:00
|
|
|
const ProFunctionDef &func, const QList<ProStringList> &argumentsList, bool *ok)
|
2009-05-18 17:46:30 +02:00
|
|
|
{
|
|
|
|
|
bool oki;
|
2010-04-27 18:39:10 +02:00
|
|
|
ProStringList ret;
|
2009-05-18 17:46:30 +02:00
|
|
|
|
|
|
|
|
if (m_valuemapStack.count() >= 100) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("ran into infinite recursion (depth > 100)."));
|
2009-06-03 19:04:10 +02:00
|
|
|
oki = false;
|
2009-05-18 17:46:30 +02:00
|
|
|
} else {
|
2010-04-27 18:39:10 +02:00
|
|
|
m_valuemapStack.push(QHash<ProString, ProStringList>());
|
2010-06-23 13:58:44 +02:00
|
|
|
m_locationStack.push(m_current);
|
2010-04-19 22:35:58 +02:00
|
|
|
int loopLevel = m_loopLevel;
|
|
|
|
|
m_loopLevel = 0;
|
2009-05-18 17:46:30 +02:00
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
ProStringList args;
|
2009-05-18 17:46:30 +02:00
|
|
|
for (int i = 0; i < argumentsList.count(); ++i) {
|
2009-08-14 17:36:07 +02:00
|
|
|
args += argumentsList[i];
|
2010-04-27 18:39:10 +02:00
|
|
|
m_valuemapStack.top()[ProString(QString::number(i+1))] = argumentsList[i];
|
2009-05-18 17:46:30 +02:00
|
|
|
}
|
2010-02-09 20:38:21 +01:00
|
|
|
m_valuemapStack.top()[statics.strARGS] = args;
|
2010-06-23 13:58:44 +02:00
|
|
|
oki = (visitProBlock(func.pro(), func.tokPtr()) != ReturnFalse); // True || Return
|
2009-05-18 17:46:30 +02:00
|
|
|
ret = m_returnValue;
|
|
|
|
|
m_returnValue.clear();
|
|
|
|
|
|
2010-04-19 22:35:58 +02:00
|
|
|
m_loopLevel = loopLevel;
|
2010-06-23 13:58:44 +02:00
|
|
|
m_current = m_locationStack.pop();
|
2010-02-09 20:38:21 +01:00
|
|
|
m_valuemapStack.pop();
|
2009-05-18 17:46:30 +02:00
|
|
|
}
|
|
|
|
|
if (ok)
|
|
|
|
|
*ok = oki;
|
|
|
|
|
if (oki)
|
|
|
|
|
return ret;
|
2010-04-27 18:39:10 +02:00
|
|
|
return ProStringList();
|
2009-05-18 17:46:30 +02:00
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBoolFunction(
|
2012-05-02 18:25:24 +02:00
|
|
|
const ProFunctionDef &func, const QList<ProStringList> &argumentsList,
|
2010-05-21 21:18:17 +02:00
|
|
|
const ProString &function)
|
|
|
|
|
{
|
|
|
|
|
bool ok;
|
|
|
|
|
ProStringList ret = evaluateFunction(func, argumentsList, &ok);
|
|
|
|
|
if (ok) {
|
|
|
|
|
if (ret.isEmpty())
|
|
|
|
|
return ReturnTrue;
|
|
|
|
|
if (ret.at(0) != statics.strfalse) {
|
|
|
|
|
if (ret.at(0) == statics.strtrue)
|
|
|
|
|
return ReturnTrue;
|
|
|
|
|
int val = ret.at(0).toQString(m_tmp1).toInt(&ok);
|
|
|
|
|
if (ok) {
|
|
|
|
|
if (val)
|
|
|
|
|
return ReturnTrue;
|
|
|
|
|
} else {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("Unexpected return value from test '%1': %2")
|
|
|
|
|
.arg(function.toQString(m_tmp1))
|
|
|
|
|
.arg(ret.join(QLatin1String(" :: "))));
|
2010-05-21 21:18:17 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ReturnFalse;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
ProStringList QMakeEvaluator::evaluateExpandFunction(
|
2010-06-01 18:43:11 +02:00
|
|
|
const ProString &func, const ushort *&tokPtr)
|
|
|
|
|
{
|
2012-05-02 18:25:24 +02:00
|
|
|
QHash<ProString, ProFunctionDef>::ConstIterator it =
|
2010-06-01 18:43:11 +02:00
|
|
|
m_functionDefs.replaceFunctions.constFind(func);
|
|
|
|
|
if (it != m_functionDefs.replaceFunctions.constEnd())
|
|
|
|
|
return evaluateFunction(*it, prepareFunctionArgs(tokPtr), 0);
|
|
|
|
|
|
|
|
|
|
//why don't the builtin functions just use args_list? --Sam
|
2010-05-31 21:07:14 +02:00
|
|
|
return evaluateExpandFunction(func, expandVariableReferences(tokPtr, 5, true));
|
2010-06-01 18:43:11 +02:00
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
ProStringList QMakeEvaluator::evaluateExpandFunction(
|
2010-04-27 18:39:10 +02:00
|
|
|
const ProString &func, const ProString &arguments)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2012-05-02 18:25:24 +02:00
|
|
|
QHash<ProString, ProFunctionDef>::ConstIterator it =
|
2010-05-11 12:24:05 +02:00
|
|
|
m_functionDefs.replaceFunctions.constFind(func);
|
|
|
|
|
if (it != m_functionDefs.replaceFunctions.constEnd())
|
|
|
|
|
return evaluateFunction(*it, prepareFunctionArgs(arguments), 0);
|
2009-05-18 17:46:30 +02:00
|
|
|
|
2010-04-27 22:00:11 +02:00
|
|
|
//why don't the builtin functions just use args_list? --Sam
|
|
|
|
|
int pos = 0;
|
2010-06-01 18:43:11 +02:00
|
|
|
return evaluateExpandFunction(func, expandVariableReferences(arguments, &pos, true));
|
|
|
|
|
}
|
2010-02-08 16:47:25 +01:00
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditionalFunction(
|
2010-04-27 18:39:10 +02:00
|
|
|
const ProString &function, const ProString &arguments)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2012-05-02 18:25:24 +02:00
|
|
|
QHash<ProString, ProFunctionDef>::ConstIterator it =
|
2010-05-11 12:24:05 +02:00
|
|
|
m_functionDefs.testFunctions.constFind(function);
|
2010-05-21 21:18:17 +02:00
|
|
|
if (it != m_functionDefs.testFunctions.constEnd())
|
|
|
|
|
return evaluateBoolFunction(*it, prepareFunctionArgs(arguments), function);
|
2009-05-18 17:46:30 +02:00
|
|
|
|
2010-04-27 22:00:11 +02:00
|
|
|
//why don't the builtin functions just use args_list? --Sam
|
|
|
|
|
int pos = 0;
|
2010-06-01 18:43:11 +02:00
|
|
|
return evaluateConditionalFunction(function, expandVariableReferences(arguments, &pos, true));
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditionalFunction(
|
2010-06-01 18:43:11 +02:00
|
|
|
const ProString &function, const ushort *&tokPtr)
|
|
|
|
|
{
|
2012-05-02 18:25:24 +02:00
|
|
|
QHash<ProString, ProFunctionDef>::ConstIterator it =
|
2010-06-01 18:43:11 +02:00
|
|
|
m_functionDefs.testFunctions.constFind(function);
|
|
|
|
|
if (it != m_functionDefs.testFunctions.constEnd())
|
|
|
|
|
return evaluateBoolFunction(*it, prepareFunctionArgs(tokPtr), function);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-06-01 18:43:11 +02:00
|
|
|
//why don't the builtin functions just use args_list? --Sam
|
2010-05-31 21:07:14 +02:00
|
|
|
return evaluateConditionalFunction(function, expandVariableReferences(tokPtr, 5, true));
|
2010-06-01 18:43:11 +02:00
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
QHash<ProString, ProStringList> *QMakeEvaluator::findValues(
|
2010-04-27 18:39:10 +02:00
|
|
|
const ProString &variableName, QHash<ProString, ProStringList>::Iterator *rit)
|
2010-02-09 20:38:21 +01:00
|
|
|
{
|
|
|
|
|
for (int i = m_valuemapStack.size(); --i >= 0; ) {
|
2010-04-27 18:39:10 +02:00
|
|
|
QHash<ProString, ProStringList>::Iterator it = m_valuemapStack[i].find(variableName);
|
2010-02-09 20:38:21 +01:00
|
|
|
if (it != m_valuemapStack[i].end()) {
|
|
|
|
|
if (it->constBegin() == statics.fakeValue.constBegin())
|
|
|
|
|
return 0;
|
|
|
|
|
*rit = it;
|
|
|
|
|
return &m_valuemapStack[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
ProStringList &QMakeEvaluator::valuesRef(const ProString &variableName)
|
2010-02-09 20:38:21 +01:00
|
|
|
{
|
2010-04-27 18:39:10 +02:00
|
|
|
QHash<ProString, ProStringList>::Iterator it = m_valuemapStack.top().find(variableName);
|
2012-07-03 12:18:47 +02:00
|
|
|
if (it != m_valuemapStack.top().end()) {
|
|
|
|
|
if (it->constBegin() == statics.fakeValue.constBegin())
|
|
|
|
|
it->clear();
|
2010-02-09 20:38:21 +01:00
|
|
|
return *it;
|
2012-07-03 12:18:47 +02:00
|
|
|
}
|
2010-02-09 20:38:21 +01:00
|
|
|
for (int i = m_valuemapStack.size() - 1; --i >= 0; ) {
|
2010-04-27 18:39:10 +02:00
|
|
|
QHash<ProString, ProStringList>::ConstIterator it = m_valuemapStack.at(i).constFind(variableName);
|
2010-02-09 20:38:21 +01:00
|
|
|
if (it != m_valuemapStack.at(i).constEnd()) {
|
2010-04-27 18:39:10 +02:00
|
|
|
ProStringList &ret = m_valuemapStack.top()[variableName];
|
2012-07-03 12:18:47 +02:00
|
|
|
if (it->constBegin() != statics.fakeValue.constBegin())
|
|
|
|
|
ret = *it;
|
2010-02-09 20:38:21 +01:00
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return m_valuemapStack.top()[variableName];
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
ProStringList QMakeEvaluator::valuesDirect(const ProString &variableName) const
|
2010-02-09 20:38:21 +01:00
|
|
|
{
|
|
|
|
|
for (int i = m_valuemapStack.size(); --i >= 0; ) {
|
2010-04-27 18:39:10 +02:00
|
|
|
QHash<ProString, ProStringList>::ConstIterator it = m_valuemapStack.at(i).constFind(variableName);
|
2010-02-09 20:38:21 +01:00
|
|
|
if (it != m_valuemapStack.at(i).constEnd()) {
|
|
|
|
|
if (it->constBegin() == statics.fakeValue.constBegin())
|
|
|
|
|
break;
|
|
|
|
|
return *it;
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-04-27 18:39:10 +02:00
|
|
|
return ProStringList();
|
2010-02-09 20:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
ProStringList QMakeEvaluator::values(const ProString &variableName) const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-04-27 18:39:10 +02:00
|
|
|
QHash<ProString, int>::ConstIterator vli = statics.varList.find(variableName);
|
2010-02-08 16:47:25 +01:00
|
|
|
if (vli != statics.varList.constEnd()) {
|
2010-02-02 19:01:23 +01:00
|
|
|
int vlidx = *vli;
|
|
|
|
|
QString ret;
|
|
|
|
|
switch ((VarName)vlidx) {
|
|
|
|
|
case V_LITERAL_WHITESPACE: ret = QLatin1String("\t"); break;
|
|
|
|
|
case V_LITERAL_DOLLAR: ret = QLatin1String("$"); break;
|
|
|
|
|
case V_LITERAL_HASH: ret = QLatin1String("#"); break;
|
2010-06-23 13:58:44 +02:00
|
|
|
case V_OUT_PWD: // the outgoing dir (shadow of _PRO_FILE_PWD_)
|
2010-02-02 19:01:23 +01:00
|
|
|
ret = m_outputDir;
|
|
|
|
|
break;
|
2010-06-23 13:58:44 +02:00
|
|
|
case V_PWD: // containing directory of most nested project/include file
|
2010-02-02 19:01:23 +01:00
|
|
|
case V_IN_PWD:
|
|
|
|
|
ret = currentDirectory();
|
|
|
|
|
break;
|
|
|
|
|
case V_DIR_SEPARATOR:
|
2011-03-18 20:41:40 +01:00
|
|
|
validateModes();
|
2010-02-02 19:01:23 +01:00
|
|
|
ret = m_option->dir_sep;
|
|
|
|
|
break;
|
|
|
|
|
case V_DIRLIST_SEPARATOR:
|
|
|
|
|
ret = m_option->dirlist_sep;
|
|
|
|
|
break;
|
2010-06-23 13:58:44 +02:00
|
|
|
case V__LINE_: // currently executed line number
|
|
|
|
|
ret = QString::number(m_current.line);
|
2010-02-02 19:01:23 +01:00
|
|
|
break;
|
2010-06-23 13:58:44 +02:00
|
|
|
case V__FILE_: // currently executed file
|
|
|
|
|
ret = m_current.pro->fileName();
|
2010-02-02 19:01:23 +01:00
|
|
|
break;
|
|
|
|
|
case V__DATE_: //current date/time
|
|
|
|
|
ret = QDateTime::currentDateTime().toString();
|
|
|
|
|
break;
|
|
|
|
|
case V__PRO_FILE_:
|
|
|
|
|
ret = m_profileStack.first()->fileName();
|
|
|
|
|
break;
|
|
|
|
|
case V__PRO_FILE_PWD_:
|
|
|
|
|
ret = m_profileStack.first()->directoryName();
|
|
|
|
|
break;
|
|
|
|
|
case V__QMAKE_CACHE_:
|
|
|
|
|
ret = m_option->cachefile;
|
|
|
|
|
break;
|
2008-12-12 16:30:31 +01:00
|
|
|
#if defined(Q_OS_WIN32)
|
2010-02-02 19:01:23 +01:00
|
|
|
case V_QMAKE_HOST_os: ret = QLatin1String("Windows"); break;
|
2010-02-05 16:20:33 +01:00
|
|
|
case V_QMAKE_HOST_name: {
|
2008-12-12 16:30:31 +01:00
|
|
|
DWORD name_length = 1024;
|
|
|
|
|
TCHAR name[1024];
|
|
|
|
|
if (GetComputerName(name, &name_length))
|
|
|
|
|
ret = QString::fromUtf16((ushort*)name, name_length);
|
2010-02-02 19:01:23 +01:00
|
|
|
break;
|
2010-02-05 16:20:33 +01:00
|
|
|
}
|
2010-02-02 19:01:23 +01:00
|
|
|
case V_QMAKE_HOST_version:
|
|
|
|
|
ret = QString::number(QSysInfo::WindowsVersion);
|
|
|
|
|
break;
|
|
|
|
|
case V_QMAKE_HOST_version_string:
|
|
|
|
|
switch (QSysInfo::WindowsVersion) {
|
|
|
|
|
case QSysInfo::WV_Me: ret = QLatin1String("WinMe"); break;
|
|
|
|
|
case QSysInfo::WV_95: ret = QLatin1String("Win95"); break;
|
|
|
|
|
case QSysInfo::WV_98: ret = QLatin1String("Win98"); break;
|
|
|
|
|
case QSysInfo::WV_NT: ret = QLatin1String("WinNT"); break;
|
|
|
|
|
case QSysInfo::WV_2000: ret = QLatin1String("Win2000"); break;
|
|
|
|
|
case QSysInfo::WV_2003: ret = QLatin1String("Win2003"); break;
|
|
|
|
|
case QSysInfo::WV_XP: ret = QLatin1String("WinXP"); break;
|
|
|
|
|
case QSysInfo::WV_VISTA: ret = QLatin1String("WinVista"); break;
|
|
|
|
|
default: ret = QLatin1String("Unknown"); break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case V_QMAKE_HOST_arch:
|
2008-12-12 16:30:31 +01:00
|
|
|
SYSTEM_INFO info;
|
|
|
|
|
GetSystemInfo(&info);
|
|
|
|
|
switch(info.wProcessorArchitecture) {
|
|
|
|
|
#ifdef PROCESSOR_ARCHITECTURE_AMD64
|
|
|
|
|
case PROCESSOR_ARCHITECTURE_AMD64:
|
|
|
|
|
ret = QLatin1String("x86_64");
|
|
|
|
|
break;
|
|
|
|
|
#endif
|
|
|
|
|
case PROCESSOR_ARCHITECTURE_INTEL:
|
|
|
|
|
ret = QLatin1String("x86");
|
|
|
|
|
break;
|
|
|
|
|
case PROCESSOR_ARCHITECTURE_IA64:
|
|
|
|
|
#ifdef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64
|
|
|
|
|
case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
|
|
|
|
|
#endif
|
|
|
|
|
ret = QLatin1String("IA64");
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
ret = QLatin1String("Unknown");
|
|
|
|
|
break;
|
|
|
|
|
}
|
2010-02-02 19:01:23 +01:00
|
|
|
break;
|
2008-12-12 16:30:31 +01:00
|
|
|
#elif defined(Q_OS_UNIX)
|
2010-02-02 19:01:23 +01:00
|
|
|
case V_QMAKE_HOST_os:
|
|
|
|
|
case V_QMAKE_HOST_name:
|
|
|
|
|
case V_QMAKE_HOST_version:
|
|
|
|
|
case V_QMAKE_HOST_version_string:
|
|
|
|
|
case V_QMAKE_HOST_arch:
|
|
|
|
|
{
|
|
|
|
|
struct utsname name;
|
|
|
|
|
const char *what;
|
|
|
|
|
if (!uname(&name)) {
|
|
|
|
|
switch (vlidx) {
|
|
|
|
|
case V_QMAKE_HOST_os: what = name.sysname; break;
|
|
|
|
|
case V_QMAKE_HOST_name: what = name.nodename; break;
|
|
|
|
|
case V_QMAKE_HOST_version: what = name.release; break;
|
|
|
|
|
case V_QMAKE_HOST_version_string: what = name.version; break;
|
|
|
|
|
case V_QMAKE_HOST_arch: what = name.machine; break;
|
|
|
|
|
}
|
try to sort out the filename encoding mess
use local8bit instead of latin1 resp. 8bit-passthrough, after all.
the situation was as follows:
- if the pro files and file names were all ascii, everything just worked
- if either contained non-ascii:
- on unix, the evaluator would work as long as the file content
encoding matched the file name encoding, and the ui would work as
long as the file name encoding was latin1 (i.e., on no modern
system)
- on windows, both would work only if the ansi code page was
latin1/cp1252 (i.e., on western systems)
i.e., even in the low-level evaluator, only native latin1 systems with
actual latin1 files worked consistently. given this situation, it makes
little sense to make an encoding adapter between the evaluator and the
ui as originally planned. instead, take the easy way out and use
local8bit - this continues to work for native latin1 systems+files in
the backend, and makes the ui work for everything the backend groks and
some more.
Reviewed-by: dt
Task-number: QTCREATORBUG-930
2010-06-08 17:49:09 +02:00
|
|
|
ret = QString::fromLocal8Bit(what);
|
2010-02-02 19:01:23 +01:00
|
|
|
}
|
|
|
|
|
}
|
2008-12-12 16:30:31 +01:00
|
|
|
#endif
|
2010-02-02 19:01:23 +01:00
|
|
|
}
|
2010-04-27 18:39:10 +02:00
|
|
|
return ProStringList(ProString(ret, NoHash));
|
2008-12-12 16:30:31 +01:00
|
|
|
}
|
|
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
ProStringList result = valuesDirect(variableName);
|
2008-12-12 16:30:31 +01:00
|
|
|
if (result.isEmpty()) {
|
2010-02-08 17:15:44 +01:00
|
|
|
if (variableName == statics.strTEMPLATE) {
|
2010-04-27 18:39:10 +02:00
|
|
|
result.append(ProString("app", NoHash));
|
2010-02-08 17:15:44 +01:00
|
|
|
} else if (variableName == statics.strQMAKE_DIR_SEP) {
|
2010-04-27 18:39:10 +02:00
|
|
|
result.append(ProString(m_option->dirlist_sep, NoHash));
|
2008-12-12 16:30:31 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2008-12-12 16:30:31 +01:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
bool QMakeEvaluator::evaluateFileDirect(
|
|
|
|
|
const QString &fileName, QMakeEvaluatorHandler::EvalFileType type,
|
2010-06-24 16:41:33 +02:00
|
|
|
ProFileEvaluator::LoadFlags flags)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-06-18 19:48:07 +02:00
|
|
|
if (ProFile *pro = m_parser->parsedProFile(fileName, true)) {
|
2010-06-23 13:58:44 +02:00
|
|
|
m_locationStack.push(m_current);
|
2010-06-24 16:41:33 +02:00
|
|
|
bool ok = (visitProFile(pro, type, flags) == ReturnTrue);
|
2010-06-23 13:58:44 +02:00
|
|
|
m_current = m_locationStack.pop();
|
2009-12-07 22:58:47 +01:00
|
|
|
pro->deref();
|
2009-05-12 17:15:54 +02:00
|
|
|
return ok;
|
2008-12-02 12:01:29 +01:00
|
|
|
} else {
|
2009-05-12 17:15:54 +02:00
|
|
|
return false;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
bool QMakeEvaluator::evaluateFile(
|
|
|
|
|
const QString &fileName, QMakeEvaluatorHandler::EvalFileType type,
|
2010-06-24 16:41:33 +02:00
|
|
|
ProFileEvaluator::LoadFlags flags)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-01-22 12:26:14 +01:00
|
|
|
if (fileName.isEmpty())
|
2009-08-04 20:39:28 +02:00
|
|
|
return false;
|
|
|
|
|
foreach (const ProFile *pf, m_profileStack)
|
2010-01-22 12:26:14 +01:00
|
|
|
if (pf->fileName() == fileName) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("circular inclusion of %1").arg(fileName));
|
2009-08-04 20:39:28 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2010-06-24 16:41:33 +02:00
|
|
|
return evaluateFileDirect(fileName, type, flags);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
bool QMakeEvaluator::evaluateFeatureFile(const QString &fileName)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-08-04 16:16:27 +02:00
|
|
|
QString fn = fileName;
|
2009-07-20 16:58:29 +02:00
|
|
|
if (!fn.endsWith(QLatin1String(".prf")))
|
|
|
|
|
fn += QLatin1String(".prf");
|
2009-08-04 16:16:27 +02:00
|
|
|
|
2011-03-18 20:03:56 +01:00
|
|
|
if ((!fileName.contains((ushort)'/') && !fileName.contains((ushort)'\\'))
|
|
|
|
|
|| !IoUtils::exists(resolvePath(fn))) {
|
2009-08-04 16:16:27 +02:00
|
|
|
if (m_option->feature_roots.isEmpty())
|
|
|
|
|
m_option->feature_roots = qmakeFeaturePaths();
|
|
|
|
|
int start_root = 0;
|
|
|
|
|
QString currFn = currentFileName();
|
2010-01-22 12:26:14 +01:00
|
|
|
if (IoUtils::fileName(currFn) == IoUtils::fileName(fn)) {
|
2009-08-04 16:16:27 +02:00
|
|
|
for (int root = 0; root < m_option->feature_roots.size(); ++root)
|
2010-02-08 11:07:18 +01:00
|
|
|
if (currFn == m_option->feature_roots.at(root) + fn) {
|
2009-08-04 16:16:27 +02:00
|
|
|
start_root = root + 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (int root = start_root; root < m_option->feature_roots.size(); ++root) {
|
|
|
|
|
QString fname = m_option->feature_roots.at(root) + fn;
|
2010-01-22 12:26:14 +01:00
|
|
|
if (IoUtils::exists(fname)) {
|
2009-08-04 16:16:27 +02:00
|
|
|
fn = fname;
|
|
|
|
|
goto cool;
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2009-08-04 16:16:27 +02:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
cool:
|
|
|
|
|
// It's beyond me why qmake has this inside this if ...
|
2010-04-27 18:39:10 +02:00
|
|
|
ProStringList &already = valuesRef(ProString("QMAKE_INTERNAL_INCLUDED_FEATURES"));
|
|
|
|
|
ProString afn(fn, NoHash);
|
|
|
|
|
if (already.contains(afn))
|
2009-08-04 16:16:27 +02:00
|
|
|
return true;
|
2010-04-27 18:39:10 +02:00
|
|
|
already.append(afn);
|
2009-08-04 16:16:27 +02:00
|
|
|
} else {
|
2010-01-22 12:26:14 +01:00
|
|
|
fn = resolvePath(fn);
|
2009-08-04 16:16:27 +02:00
|
|
|
}
|
|
|
|
|
|
2011-05-31 19:19:34 +02:00
|
|
|
#ifdef PROEVALUATOR_CUMULATIVE
|
2010-06-22 12:02:53 +02:00
|
|
|
bool cumulative = m_cumulative;
|
|
|
|
|
m_cumulative = false;
|
2011-05-31 19:19:34 +02:00
|
|
|
#endif
|
2009-08-04 20:48:22 +02:00
|
|
|
|
2010-06-22 12:02:53 +02:00
|
|
|
// The path is fully normalized already.
|
2012-05-02 15:43:12 +02:00
|
|
|
bool ok = evaluateFileDirect(fn, QMakeEvaluatorHandler::EvalFeatureFile,
|
2010-06-24 16:41:33 +02:00
|
|
|
ProFileEvaluator::LoadProOnly);
|
2009-08-04 20:48:22 +02:00
|
|
|
|
2011-05-31 19:19:34 +02:00
|
|
|
#ifdef PROEVALUATOR_CUMULATIVE
|
2010-06-22 12:02:53 +02:00
|
|
|
m_cumulative = cumulative;
|
2011-05-31 19:19:34 +02:00
|
|
|
#endif
|
2010-06-22 12:02:53 +02:00
|
|
|
return ok;
|
2009-08-04 16:16:27 +02:00
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
bool QMakeEvaluator::evaluateFileInto(
|
|
|
|
|
const QString &fileName, QMakeEvaluatorHandler::EvalFileType type,
|
2012-05-02 18:25:24 +02:00
|
|
|
QHash<ProString, ProStringList> *values, ProFunctionDefs *funcs, EvalIntoMode mode)
|
2009-08-04 16:16:27 +02:00
|
|
|
{
|
2010-06-18 19:48:07 +02:00
|
|
|
ProFileEvaluator visitor(m_option, m_parser, m_handler);
|
2011-05-31 19:19:34 +02:00
|
|
|
#ifdef PROEVALUATOR_CUMULATIVE
|
2009-08-04 16:16:27 +02:00
|
|
|
visitor.d->m_cumulative = false;
|
2011-05-31 19:19:34 +02:00
|
|
|
#endif
|
2010-06-24 14:13:50 +02:00
|
|
|
visitor.d->m_outputDir = m_outputDir;
|
2010-06-22 12:07:27 +02:00
|
|
|
// visitor.d->m_valuemapStack.top() = *values;
|
2009-08-10 17:27:07 +02:00
|
|
|
if (funcs)
|
|
|
|
|
visitor.d->m_functionDefs = *funcs;
|
2010-06-22 12:07:27 +02:00
|
|
|
if (mode == EvalWithDefaults)
|
|
|
|
|
visitor.d->evaluateFeatureFile(QLatin1String("default_pre.prf"));
|
2010-06-24 16:41:33 +02:00
|
|
|
if (!visitor.d->evaluateFile(fileName, type,
|
|
|
|
|
(mode == EvalWithSetup) ? ProFileEvaluator::LoadAll : ProFileEvaluator::LoadProOnly))
|
2009-08-04 16:16:27 +02:00
|
|
|
return false;
|
2010-02-09 20:38:21 +01:00
|
|
|
*values = visitor.d->m_valuemapStack.top();
|
2010-06-22 12:07:27 +02:00
|
|
|
// if (funcs)
|
|
|
|
|
// *funcs = visitor.d->m_functionDefs;
|
2009-08-04 16:16:27 +02:00
|
|
|
return true;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:43:12 +02:00
|
|
|
void QMakeEvaluator::evalError(const QString &message) const
|
2009-08-12 13:00:21 +02:00
|
|
|
{
|
|
|
|
|
if (!m_skipLevel)
|
2011-03-21 15:43:56 +01:00
|
|
|
m_handler->evalError(m_current.line ? m_current.pro->fileName() : QString(),
|
|
|
|
|
m_current.line, message);
|
2009-08-12 13:00:21 +02:00
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// ProFileEvaluator
|
|
|
|
|
//
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2010-02-08 16:47:25 +01:00
|
|
|
void ProFileEvaluator::initialize()
|
|
|
|
|
{
|
2012-05-02 15:43:12 +02:00
|
|
|
QMakeEvaluator::initStatics();
|
2010-02-08 16:47:25 +01:00
|
|
|
}
|
|
|
|
|
|
2012-05-02 15:39:02 +02:00
|
|
|
ProFileEvaluator::ProFileEvaluator(QMakeGlobals *option, QMakeParser *parser,
|
2012-05-02 15:43:12 +02:00
|
|
|
QMakeEvaluatorHandler *handler)
|
|
|
|
|
: d(new QMakeEvaluator(option, parser, handler))
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ProFileEvaluator::~ProFileEvaluator()
|
|
|
|
|
{
|
|
|
|
|
delete d;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ProFileEvaluator::contains(const QString &variableName) const
|
|
|
|
|
{
|
2010-04-27 18:39:10 +02:00
|
|
|
return d->m_valuemapStack.top().contains(ProString(variableName));
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-15 22:51:37 +02:00
|
|
|
QString ProFileEvaluator::value(const QString &variable) const
|
|
|
|
|
{
|
|
|
|
|
const QStringList &vals = values(variable);
|
|
|
|
|
if (!vals.isEmpty())
|
|
|
|
|
return vals.first();
|
|
|
|
|
|
|
|
|
|
return QString();
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
QStringList ProFileEvaluator::values(const QString &variableName) const
|
|
|
|
|
{
|
2011-04-20 21:16:17 +02:00
|
|
|
const ProStringList &values = d->values(ProString(variableName));
|
|
|
|
|
QStringList ret;
|
|
|
|
|
ret.reserve(values.size());
|
|
|
|
|
foreach (const ProString &str, values)
|
|
|
|
|
ret << d->expandEnvVars(str.toQString());
|
|
|
|
|
return ret;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QStringList ProFileEvaluator::values(const QString &variableName, const ProFile *pro) const
|
|
|
|
|
{
|
2010-02-09 14:58:59 +01:00
|
|
|
// It makes no sense to put any kind of magic into expanding these
|
2011-04-20 18:19:33 +02:00
|
|
|
const ProStringList &values = d->m_valuemapStack.at(0).value(ProString(variableName));
|
|
|
|
|
QStringList ret;
|
|
|
|
|
ret.reserve(values.size());
|
|
|
|
|
foreach (const ProString &str, values)
|
|
|
|
|
if (str.sourceFile() == pro)
|
2011-04-20 21:16:17 +02:00
|
|
|
ret << d->expandEnvVars(str.toQString());
|
2011-04-20 18:19:33 +02:00
|
|
|
return ret;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2012-06-11 21:56:05 +02:00
|
|
|
QString ProFileEvaluator::sysrootify(const QString &path, const QString &baseDir) const
|
|
|
|
|
{
|
|
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
|
Qt::CaseSensitivity cs = Qt::CaseInsensitive;
|
|
|
|
|
#else
|
|
|
|
|
Qt::CaseSensitivity cs = Qt::CaseSensitive;
|
|
|
|
|
#endif
|
|
|
|
|
const bool isHostSystemPath =
|
|
|
|
|
d->m_option->sysroot.isEmpty() || path.startsWith(d->m_option->sysroot, cs)
|
|
|
|
|
|| path.startsWith(baseDir, cs) || path.startsWith(d->m_outputDir, cs);
|
|
|
|
|
|
|
|
|
|
return isHostSystemPath ? path : d->m_option->sysroot + path;
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-10 13:37:02 +02:00
|
|
|
QStringList ProFileEvaluator::absolutePathValues(
|
|
|
|
|
const QString &variable, const QString &baseDirectory) const
|
|
|
|
|
{
|
|
|
|
|
QStringList result;
|
|
|
|
|
foreach (const QString &el, values(variable)) {
|
2011-01-05 17:56:49 +01:00
|
|
|
QString absEl = IoUtils::isAbsolutePath(el)
|
2012-06-11 21:56:05 +02:00
|
|
|
? sysrootify(el, baseDirectory) : IoUtils::resolvePath(baseDirectory, el);
|
2010-01-22 12:26:14 +01:00
|
|
|
if (IoUtils::fileType(absEl) == IoUtils::FileIsDir)
|
|
|
|
|
result << QDir::cleanPath(absEl);
|
2009-07-10 13:37:02 +02:00
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QStringList ProFileEvaluator::absoluteFileValues(
|
|
|
|
|
const QString &variable, const QString &baseDirectory, const QStringList &searchDirs,
|
|
|
|
|
const ProFile *pro) const
|
|
|
|
|
{
|
|
|
|
|
QStringList result;
|
|
|
|
|
foreach (const QString &el, pro ? values(variable, pro) : values(variable)) {
|
2010-01-22 12:26:14 +01:00
|
|
|
QString absEl;
|
|
|
|
|
if (IoUtils::isAbsolutePath(el)) {
|
2012-06-11 21:56:05 +02:00
|
|
|
const QString elWithSysroot = sysrootify(el, baseDirectory);
|
2011-01-05 17:56:49 +01:00
|
|
|
if (IoUtils::exists(elWithSysroot)) {
|
|
|
|
|
result << QDir::cleanPath(elWithSysroot);
|
2009-07-10 13:37:02 +02:00
|
|
|
goto next;
|
|
|
|
|
}
|
2011-01-05 17:56:49 +01:00
|
|
|
absEl = elWithSysroot;
|
2009-07-10 13:37:02 +02:00
|
|
|
} else {
|
|
|
|
|
foreach (const QString &dir, searchDirs) {
|
2010-01-22 12:26:14 +01:00
|
|
|
QString fn = dir + QLatin1Char('/') + el;
|
|
|
|
|
if (IoUtils::exists(fn)) {
|
|
|
|
|
result << QDir::cleanPath(fn);
|
2009-07-10 13:37:02 +02:00
|
|
|
goto next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (baseDirectory.isEmpty())
|
|
|
|
|
goto next;
|
2010-01-22 12:26:14 +01:00
|
|
|
absEl = baseDirectory + QLatin1Char('/') + el;
|
2009-07-10 13:37:02 +02:00
|
|
|
}
|
|
|
|
|
{
|
2010-01-22 12:26:14 +01:00
|
|
|
absEl = QDir::cleanPath(absEl);
|
|
|
|
|
int nameOff = absEl.lastIndexOf(QLatin1Char('/'));
|
2010-06-10 17:14:54 +02:00
|
|
|
QString absDir = d->m_tmp1.setRawData(absEl.constData(), nameOff);
|
2010-01-22 12:26:14 +01:00
|
|
|
if (IoUtils::exists(absDir)) {
|
2010-06-10 17:14:54 +02:00
|
|
|
QString wildcard = d->m_tmp2.setRawData(absEl.constData() + nameOff + 1,
|
2010-01-22 12:26:14 +01:00
|
|
|
absEl.length() - nameOff - 1);
|
2009-07-10 13:37:02 +02:00
|
|
|
if (wildcard.contains(QLatin1Char('*')) || wildcard.contains(QLatin1Char('?'))) {
|
2010-10-21 19:53:29 +02:00
|
|
|
wildcard.detach(); // Keep m_tmp out of QRegExp's cache
|
2010-01-22 12:26:14 +01:00
|
|
|
QDir theDir(absDir);
|
2009-07-10 13:37:02 +02:00
|
|
|
foreach (const QString &fn, theDir.entryList(QStringList(wildcard)))
|
2010-02-08 17:15:44 +01:00
|
|
|
if (fn != statics.strDot && fn != statics.strDotDot)
|
2010-01-22 12:26:14 +01:00
|
|
|
result << absDir + QLatin1Char('/') + fn;
|
2009-07-10 13:37:02 +02:00
|
|
|
} // else if (acceptMissing)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
next: ;
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-15 20:50:57 +02:00
|
|
|
ProFileEvaluator::TemplateType ProFileEvaluator::templateType() const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-04-27 18:39:10 +02:00
|
|
|
const ProStringList &templ = d->values(statics.strTEMPLATE);
|
2008-12-02 12:01:29 +01:00
|
|
|
if (templ.count() >= 1) {
|
2010-06-24 15:17:28 +02:00
|
|
|
const QString &t = templ.at(0).toQString();
|
2009-05-25 15:58:58 +02:00
|
|
|
if (!t.compare(QLatin1String("app"), Qt::CaseInsensitive))
|
2008-12-02 12:01:29 +01:00
|
|
|
return TT_Application;
|
2009-05-25 15:58:58 +02:00
|
|
|
if (!t.compare(QLatin1String("lib"), Qt::CaseInsensitive))
|
2008-12-02 12:01:29 +01:00
|
|
|
return TT_Library;
|
2009-05-25 15:58:58 +02:00
|
|
|
if (!t.compare(QLatin1String("script"), Qt::CaseInsensitive))
|
2008-12-02 12:01:29 +01:00
|
|
|
return TT_Script;
|
2011-05-05 17:42:35 +02:00
|
|
|
if (!t.compare(QLatin1String("aux"), Qt::CaseInsensitive))
|
|
|
|
|
return TT_Aux;
|
2009-05-25 15:58:58 +02:00
|
|
|
if (!t.compare(QLatin1String("subdirs"), Qt::CaseInsensitive))
|
2008-12-02 12:01:29 +01:00
|
|
|
return TT_Subdirs;
|
|
|
|
|
}
|
|
|
|
|
return TT_Unknown;
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-24 16:41:33 +02:00
|
|
|
bool ProFileEvaluator::accept(ProFile *pro, LoadFlags flags)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2012-05-02 15:43:12 +02:00
|
|
|
return d->visitProFile(pro, QMakeEvaluatorHandler::EvalProjectFile, flags) == QMakeEvaluator::ReturnTrue;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString ProFileEvaluator::propertyValue(const QString &name) const
|
|
|
|
|
{
|
2010-06-24 18:57:07 +02:00
|
|
|
return d->propertyValue(name, false);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2011-05-31 19:19:34 +02:00
|
|
|
#ifdef PROEVALUATOR_CUMULATIVE
|
2008-12-12 18:10:42 +01:00
|
|
|
void ProFileEvaluator::setCumulative(bool on)
|
|
|
|
|
{
|
|
|
|
|
d->m_cumulative = on;
|
|
|
|
|
}
|
2011-05-31 19:19:34 +02:00
|
|
|
#endif
|
2008-12-12 18:10:42 +01:00
|
|
|
|
2008-12-12 16:30:31 +01:00
|
|
|
void ProFileEvaluator::setOutputDir(const QString &dir)
|
|
|
|
|
{
|
|
|
|
|
d->m_outputDir = dir;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
QT_END_NAMESPACE
|